三、Mybatis接口映射(注解)
传统的mapper.xml+接口使用接口映射相对较麻烦
所以我们可以使用注解来简化开发
支持的注解有以下:
MyBatis可以利用SQL映射文件来配置,也可以利用Annotation来设置。MyBatis提供的一些基本注解如下表所示。
注解 |
目标 |
相对应的 XML |
描述 |
@CacheNamespace |
类 |
<cache> |
为给定的命名空间 (比如类)配置缓存。属性:implemetation,eviction, flushInterval,size,readWrite,blocking和 properties。 |
@Property |
N/A |
<property> |
Specifies the property value or placeholder(can replace by configuration properties that defined at themybatis-config.xml). Attributes: name, value. (Available on MyBatis 3.4.2+) |
@CacheNamespaceRef |
类 |
<cacheRef> |
参照另外一个命名空间的缓存来使用。属性:value, name。 If you use this annotation, you should be specified either value or name attribute. For the value attribute specify a java type indicating the namespace(the namespace name become a FQCN of specified java type), and for the name attribute(this attribute is available since 3.4.2) specify a name indicating the namespace. |
@ConstructorArgs |
方法 |
<constructor> |
收集一组结果传递给一个劫夺对象的构造方法。属性:value,是形式参数的数组。 |
@Arg |
N/A |
· <arg> · <idArg> |
单独的构造方法参数 , 是 ConstructorArgs集合的一部分。属性: id,column,javaType,typeHandler。 id属性是布尔值, 来标识用于比较的属性,和<idArg>XML元素相似。 |
@TypeDiscriminator |
方法 |
<discriminator> |
一组实例值被用来决定结果映射的表现。属性: column, javaType, jdbcType, typeHandler,cases。cases属性就是实例的数组。 |
@Case |
N/A |
<case> |
单独实例的值和它对应的映射。属性: value,type,results。Results属性是结果数组,因此这个注解和实际的 ResultMap很相似,由下面的 Results注解指定。 |
@Results |
方法 |
<resultMap> |
结果映射的列表, 包含了一个特别结果列如何被映射到属性或字段的详情。属性:value, id。value属性是 Result 注解的数组。这个id的属性是结果映射的名称。 |
@Result |
N/A |
· <result> · <id> |
在列和属性或字段之间的单独结果映射。属性:id,column, property, javaType ,jdbcType ,type Handler, one,many。id属性是一个布尔值,表示了应该被用于比较(和在 XML 映射中的<id>相似)的属性。one属性是单独的联系,和 <association>相似 ,而 many 属性是对集合而言的 , 和 <collection>相似。它们这样命名是为了避免名称冲突。 |
@One |
N/A |
<association> |
复杂类型的单独属性值映射。属性: select,已映射语句(也就是映射器方法)的完全限定名,它可以加载合适类型的实例。注意:联合映射在注解 API 中是不支持的。这是因为 Java注解的限制,不允许循环引用。 fetchType会覆盖全局的配置参数lazyLoadingEnabled。 |
@Many |
N/A |
<collection> |
映射到复杂类型的集合属性。属性:select,已映射语句(也就是映射器方法)的全限定名,它可以加载合适类型的实例的集合,fetchType会覆盖全局的配置参数lazyLoadingEnabled。 注意联合映射在注解 API中是不支持的。这是因为 Java注解的限制,不允许循环引用 |
@MapKey |
方法 |
复杂类型的集合属性映射。属性 : select,是映射语句(也就是映射器方法)的完全限定名,它可以加载合适类型的一组实例。注意:联合映射在 Java 注解中是不支持的。这是因为 Java注解的限制,不允许循环引用。 |
|
@Options |
方法 |
映射语句的属性 |
这个注解提供访问交换和配置选项的宽广范围,它们通常在映射语句上作为属性出现。而不是将每条语句注解变复杂,Options注解提供连贯清晰的方式来访问它们。属性:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , fetchSize=-1 , , timeout=-1 useGeneratedKeys=false , keyProperty=”id” , keyColumn=”” , resultSets=””。理解 Java注解是很重要的,因为没有办法来指定“null”作为值。因此,一旦你使用了 Options注解,语句就受所有默认值的支配。要注意什么样的默认值来避免不期望的行为。 |
· @Insert · @Update · @Delete · @Select |
方法 |
· <insert> · <update> · <delete> · <select> |
这些注解中的每一个代表了执行的真实 SQL。它们每一个都使用字符串数组 (或单独的字符串)。如果传递的是字符串数组,它们由每个分隔它们的单独空间串联起来。这就当用 Java代码构建 SQL时避免了“丢失空间”的问题。然而,如果你喜欢,也欢迎你串联单独的字符串。属性:value,这是字符串数组用来组成单独的 SQL 语句。 |
· @InsertProvider · @UpdateProvider · @DeleteProvider · @SelectProvider |
方法 |
· <insert> · <update> · <delete> · <select> |
这些可选的 SQL 注解允许你指定一个类名和一个方法在执行时来返回运行允许创建动态的 SQL。基于执行的映射语句, MyBatis 会实例化这个类,然后执行由 provider指定的方法. You can pass objects that passed to arguments of a mapper method, "Mapper interface type" and "Mapper method" via theProviderContext(available since MyBatis 3.4.5 or later) as method argument. (In MyBatis 3.4 or later, it's allow multiple parameters)属性: type,method。type属性是类。method属性是方法名。注意:这节之后是对类的讨论,它可以帮助你以干净,容于阅读的方式来构建动态 SQL。 |
@Param |
Parameter |
N/A |
如果你的映射器的方法需要多个参数,这个注解可以被应用于映射器的方法参数来给每个参数一个名字。否则,多参数将会以它们的顺序位置来被命名 (不包括任何 RowBounds参数) 比如。 #{param1} , #{param2}等 , 这是默认的。使用 @Param(“person”),参数应该被命名为 #{person}。 |
@SelectKey |
方法 |
<selectKey> |
该注解复制了<selectKey>的功能,用在注解了@Insert, @InsertProvider, @Update or@UpdateProvider的方法上。在其他方法上将被忽略。如果你指定了一个@SelectKey注解,然后Mybatis将忽略任何生成的key属性通过设置@Options,或者配置属性。属性: statement是要执行的sql语句的字符串数组,keyProperty是需要更新为新值的参数对象属性, before可以是true或者false分别代表sql语句应该在执行insert之前或者之后, resultType是keyProperty的Java类型, statementType是语句的类型,取Statement, PreparedStatement和CallableStatement对应的STATEMENT, PREPARED或者CALLABLE其中一个,默认是PREPARED。 |
@ResultMap |
方法 |
N/A |
这个注解给@Select或者@SelectProvider提供在XML映射中的<resultMap>的id。这使得注解的select可以复用那些定义在XML中的ResultMap。如果同一select注解中还存在@Results或者@ConstructorArgs,那么这两个注解将被此注解覆盖。 |
@ResultType |
Method |
N/A |
当使用结果处理器时启用此注解。这种情况下,返回类型为void,所以Mybatis必须有一种方式决定对象的类型,用于构造每行数据。如果有XML的结果映射,使用@ResultMap注解。如果结果类型在XML的<select>节点中指定了,就不需要其他的注解了。其他情况下则使用此注解。比如,如果@Select注解在一个方法上将使用结果处理器,返回类型必须是void并且这个注解(或者@ResultMap)是必须的。这个注解将被忽略除非返回类型是void。 |
@Flush |
方法 |
N/A |
如果这个注解使用了,它将调用定义在Mapper接口中的SqlSession#flushStatements()方法。(Mybatis 3.3或者以上) |
这些注解的用法有很多,这里只是简单介绍如何简单的使用注解代替mapper.xml文件,下几篇文章会详细解释其他几种注解的使用
本文主要的注解有 @Select、@Delete、@Insert、@update、和@Param
1. Mybatis.xml配置文件(Mybatis的大脑)
1).指定jdbc.properties文件的路径
使用<propertiesresource=" "></properties>标签
2).配置jdbc环境
<!-- 配置jdbc环境 --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <!-- 配置数据库连接信息 根据el表达式取值--> <dataSourcetype="POOLED"> <propertyname="driver"value="${driverClass}"/> <propertyname="url"value="${url}"/> <propertyname="username"value="${user}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments> |
3).配置接口映射
因为是注解使用接口映射,所以这里不需要配置mapper.xml文件,直接使用<mapperclass=" "/>标签,直接配置接口的全类名(包名+接口名)
<mappers> <!-- 注册接口 如果使用的是注解则不需要mappers文件--> <!-- mapper 接口的全类名 --> <mapperclass="cn.et.fuqiang.interfaceMap.xml.InterfaceMyUser"/> </mappers> |
|
详细配置
Mybatis.xml |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 指定jdbc的配置文件位置 --> <propertiesresource="cn/et/fuqiang/interfaceMap/xml/jdbc.properties"></properties> <!-- 配置jdbc环境 --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <!-- 配置数据库连接信息 --> <dataSourcetype="POOLED"> <propertyname="driver"value="${driverClass}"/> <propertyname="url"value="${url}"/> <propertyname="username"value="${user}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments>
<!-- 使用接口映射 配置查询语句 --> <mappers> <!-- 注册接口 如果使用的是注解则不需要mappers文件--> <mapperclass="cn.et.fuqiang.interfaceMap.xml.InterfaceMyUser"/> </mappers>
</configuration> |
2. 定义接口和添加注解
因为我们要用注解替换mapper.xml文件,所以所有配置的重点都在定义的mapper接中。
注解的使用大大的简化了mybatis的使用,我们只需要在方法上声明一个注解,然后写上sql语句,需要用什么类型接受返回的结果,就将方法的返回值写为什么类型。
参数的设置与通常的方法一样。
以查询方法为例:
该注解中写查询语句
@Select(“select * from myuser where userid=#{0}”)
public Map<String,Object>queryMyUserById(Integeruserid);
方法的返回类型
使用@Select注解需要什么类型的返回值,直接将方法的返回类型设置为什么
参数
直接将sql语句中需要的参数设置在形参中,如果sql语句中要使用到形参的参数名,则可以在形参前加@Param(“参数名”)注解,然后在方法中直接使用
Sql语句中获取参数的值:
1. 根据索引获取
从0开始(比如形参中有两个参数,索引就是0,1)
2. 根据默认的参数名获取
从param1开始(比如形参中有两个参数,默认的属性名就是param1,param2)
3. 根据自定义名获取
在形参的参数前使用 function name(@Param(“name”)Stringname)
则可以直接使用name
两种表达式:
el表达式取值(${})
只能用在形参中指定的名称 和 默认的参数名 param1,2,3…. 名字来取值,不能根据索引取值因为el表达式会把索引当运算的数字
注意:
el表达式取值的方法相当于字符串的拼接如果是字符串的话需要自己添加单引号 如:name=’${param1}’)
所以使用el表达式无法防止sql注入
ognl表达式取值(#{})
可以根据上面的三种的任意一种取值,并且取值的方法是以? 号的方式,相当与使用jdbc中 预编译的sql PreparedStatement 方法传入参数的,所以可以防止sql注入。
下面对@Update、@Insert、@Delete和@SelectKey演示
|
package cn.et.fuqiang.interfaceMap.annotation;
import java.util.Map;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectKey; import org.apache.ibatis.annotations.Update;
public interface InterfaceMyUser { @Select("select * from myuser where userid=#{0}") public Map<String,Object> queryMyUserById(Integer userid);
@Update("update myuser set username='${username}',userage=#{userage} where userid=#{0}") public void updateUserByMap(Integer userid,@Param("username")String username,@Param("userage") Integer userage);
@SelectKey(before=true,keyProperty="userid",resultType=int.class,statement="select nvl(max(userid),0)+1 from myuser") @Insert("insert into myuser(userid,username,userage) values(#{userid},#{username},#{userage})") public void saveUserByMap(Map<String,Object> map);
@Delete("delete from myuser where userid=#{param1}") public void deleteUserById(Integer userid);
} |
在update中使用到了@SelectKey注解,该方法可以用来在插入和修改的时候,查询序列,或者是做一个简单的子查询返回一个需要的值
注意:@Update、@Insert和@Delete没有返回值所以方法的返回类型需要写为
Void
所有代码实现
Jdbc.properties文件的配置
url=jdbc:oracle:thin:@localhost:1521:orcl user=mybatis password=mybatis driverClass=oracle.jdbc.OracleDriver |
Mybatis.xml配置文件的配置
mybatis.xml |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 指定jdbc的配置文件位置 --> <propertiesresource="cn/et/fuqiang/interfaceMap/annotation/jdbc.properties"></properties> <!-- 配置jdbc环境 --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <!-- 配置数据库连接信息 --> <dataSourcetype="POOLED"> <propertyname="driver"value="${driverClass}"/> <propertyname="url"value="${url}"/> <propertyname="username"value="${user}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments>
<!-- 使用接口映射 配置查询语句 --> <mappers> <!-- 注册接口 如果使用的是注解则不需要mappers文件--> <mapperclass="cn.et.fuqiang.interfaceMap.annotation.InterfaceMyUser"/> </mappers>
</configuration>
|
接口代码
InterfaceMyUser.java |
package cn.et.fuqiang.interfaceMap.annotation;
import java.util.Map;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectKey; import org.apache.ibatis.annotations.Update;
public interface InterfaceMyUser { @Select("select * from myuser where userid=#{0}") public Map<String,Object> queryMyUserById(Integer userid); /** * 从sql语句中 获取参数 有多中方式 * 不能根据索引取值因为el表达式会把索引当运算的数字 * el表达式 ${} 只能用在形参中指定的名称 来获取 和 param1 名字 (获取值得方法相当于字符串的拼接 如果是字符串的话要用引号) * ognl表达式 #{} 可以根据传入的变量名来获取值,也可以根据上面两种方式 (获取值得方法是防注入的,?会用问号代替) * 默认是根据 形参的索引 从0开始 * * 如果要使用形参的参数名作为键 则需要在该形参前指定 @param("对应的名字") * * @param userid * @param username * @param userage */ @Update("update myuser set username='${username}',userage=#{userage} where userid=#{0}") public void updateUserByMap(Integer userid,@Param("username")String username,@Param("userage") Integer userage); @SelectKey(before=true,keyProperty="userid",resultType=int.class,statement="select nvl(max(userid),0)+1 from myuser") @Insert("insert into myuser(userid,username,userage) values(#{userid},#{username},#{userage})") public void saveUserByMap(Map<String,Object> map); @Delete("delete from myuser where userid=#{param1}") public void deleteUserById(Integer userid);
} |
测试类代码
InterfaceMapAnnotationTest.java |
package cn.et.fuqiang.interfaceMap.annotation;
import java.io.InputStream; import java.util.HashMap; import java.util.Map;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test;
public class InterfaceMapAnnotationTest { private static SqlSession session; private static InterfaceMyUser mapper=null; static{ //mybatis的配置文件 String resource = "mybatis.xml"; //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件) InputStream is = InterfaceMapAnnotationTest.class.getResourceAsStream(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) //Reader reader = Resources.getResourceAsReader(resource); //构建sqlSession的工厂 //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //创建能执行映射文件中sql的sqlSession session = sessionFactory.openSession(); mapper=session.getMapper(InterfaceMyUser.class); }
//@Test public void quesrUserById(){ System.out.println(mapper.queryMyUserById(2)); }
//@Test public void deleteUserByID(){ mapper.deleteUserById(3); session.commit(); }
//@Test public void insertUserByMap(){ Map<String,Object> map = new HashMap<String,Object>(); map.put("username", "wfq"); map.put("userage", 120); mapper.saveUserByMap(map); session.commit(); }
@Test public void updateUserByMap(){ mapper.updateUserByMap(2,"wava",100); session.commit(); } } |
来源:CSDN
作者:王福强
链接:https://blog.csdn.net/wfq784967698/article/details/78785576