关于MyBatis框架 MyBatis框架的主要作用:实现并简化数据库编程。
MyBatis框架的依赖项 MyBatis框架的依赖项是:mybatis,但,通常还应该再添加:mybatis-spring、spring-jdbc、mysql或其它数据库的依赖项、数据库连接池的依赖项(commons-dbcp / commons-dbcp2 / Druid / Hikari等)、测试
在Spring Boot项目中,只需要添加mybatis-spring-boot-starter即可包含mybatis、mybatis-spring、spring-jdbc、默认的数据库连接池。
关于Mapper接口 使用MyBatis时,需要使用Mapper接口来封装访问数据的抽象方法,这些接口可以自行放在任何位置,但需要通过注解来指定,使得MyBatis框架能找到这些接口!可以:
【推荐】在配置类上使用@MapperScan注解,来配置Mapper接口所在的根包(其子孙级包中的Mapper接口也会被找到) 注意:配置的包下,不能有Mapper接口以外的其它接口
【不推荐】在各Mapper接口上添加@Mapper注解
所有的数据访问功能都应该在接口中定义抽象方法,关于抽象方法:
返回值类型:如果需要执行的SQL语句是增、删、改类型的,应该使用int作为返回值类型,表示“受影响的行数”,其实也可以使用void,表示不关心受影响的行数,但不推荐;如果需要执行的SQL语句是查询类型的,只需要保证声明的返回值类型足以存放你需要的查询结果即可
方法名称:自定义,不建议重载
《阿里巴巴Java开发手册》中的参考:
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。
参数列表:根据需要执行的SQL语句中的参数来设计,并且,如果参数数量较多,可以封装成自定义数据类型,并使用自定义数据类型作为方法的参数,另外,对于未封装的简单数据类型的参数(例如基本数据类型及对应的包装类、String类),只要参数的数量超过1个,强烈建议在各参数上使用@Param注解配置参数名称,例如:
void getLoginInfoByUsernameAndPassword(
@Param("username") String username, @Param("password") String password);
关于@Param注解
通常,如果抽象方法中声明了简单类型的参数,在配置SQL语句时,可以使用#{}格式的占位符来表示参数的值,例如:
AlbumStandardVO getStandardById(Long id); SELECT id, name, description, sort FROM pms_album WHERE id=#{xxx} 其实,以上配置SQL语句时,#{}中的名称是很随意的,并不一定需要是抽象方法中的参数的名称!之所以是这样,主要因为:
在Java语言中,默认情况下,所有局部的量(方法内部的局部变量、方法的参数)的名称都会在编译时丢失
此抽象方法只有1个参数,MyBatis会自动的去找那唯一的参数,所以,名称并不重要
由于局部的量的名称会丢失,且方法只有1个参数时,MyBatis就会使用唯一的那个参数值,但是,如果抽象方法有2个或更多个参数,MyBatis就不知道把哪个参数值传到哪个#{}占位符对应的位置!为了解决此问题,MyBatis使用了@Param注解,通过此注解来配置参数的名称,并且,在配置SQL时,应该使用注解中配置名字,例如:
AdminStandardVO getLoginInfoByUsernameAndPassword( @Param("username") String var1, @Param("password") String var2); SELECT * FROM ams_admin WHERE username=#{username} AND password=#{password} 另外,在整合了Spring Boot后,使用的mybatis-spring-boot-starter对编译期进行了干预,保留了抽象方法的参数名称,所以,在Spring Boot中,即使不使用@Param注解来配置参数名称,也能够正确的找到各参数!通常,为了避免出问题,仍建议使用@Param注解配置参数名称!
关于使用注解来配置SQL语句 在使用MyBatis时,可以在抽象方法上使用@Insert / @Delete / @Update / @Select注解来配置SQL语句,例如:
public interface AlbumMapper {
@Select("select count(*) from pms_album")
int count();
} 但是,并不推荐使用这种做法,主要原因有:
不适合编写较长篇幅的SQL语句
不适合需要添加其它配置的数据访问
不适合与DBA协同工作
关于使用XML来配置SQL语句 在Spring Boot项目中,需要通过配置文件中的mybatis.mapper-locations属性来配置XML文件的位置,如果使用的是MyBatis-Plus,则需要通过mybatis-plus.mapper-locations属性来配置XML文件的位置。
提示:如果使用的不是Spring Boot项目,则需要配置SqlSessionFactoryBean类型的对象来指定XML文件的位置。
在XML文件内部的配置:
此文件的根标签必须是,且必须配置namespace属性,以指定对应的Mapper接口的全限定名
在标签的子级,使用 / / / 标签配置SQL语句,这些标签必须配置id属性,取值为抽象方法的名称,在这些标签内部,配置抽象方法对应的SQL语句 如果对应的数据表中的ID是自动编号的,在配置标签时,强烈建议配置useGeneratedKeys="true"和keyProperty="id"这2个属性,以获取成功插入的数据的自动编号ID值 在标签上,必须配置resultType和resultMap这2个属性中的其中1个,使用resultType时,取值为抽象方法的返回值类型的全限定名,使用resultMap时,取值为对应的标签的id属性值
动态SQL之标签:用于对参数进行遍历
collection属性:指定被遍历的参数,当抽象方法的参数只有1个,且没有添加@Param注解时,如果参数是List集合,则此属性取值为list,如果参数是数组或可变参数,则此属性取值为array,如果抽象方法的参数有多个或配置了@Param注解,则此属性取值为@Param注解中配置的名称
item属性:自定义此值,表示遍历过程中各元素的变量名
separator属性:遍历过程中生成各值时,各值之间的分隔符号
动态SQL之标签:用于对参数进行判断,例如:
UPDATE pms_album name=#{name}, description=#{description}, sort=#{sort}, WHERE id=#{id}动态SQL之系列标签,用于实现类似Java语言中if...else的效果,例如:
满足条件时的代码片段 不满足条件时的代码片段 标签与标签,用于封装SQL语句片段(通常是字段列表)并引用封装的SQL语句片段,例如: SELECT FROM ams_role ORDER BY sort DESC, id id, name 提示:在IntelliJ IDEA中,在标签中直接写字段列表会提示错误,但这并不影响运行,如果不希望看到报错的红色波浪线,可以改为: id, name [SpringBoot]xml写mapper&设置自动提示_万物更新_的博客-CSDN博客MyBatis的缓存机制 MyBatis框架存在缓存机制,表现为:当执行查询后,可以将查询结果暂时保存到应用程序服务器中(即使返回了查询结果,也不会销毁这个数据),后续再次查询时,就可以将此前的查询结果直接返回,以此提高“查询”效率。
MyBatis框架有2种缓存机制,分别称之为一级缓存和二级缓存。
一级缓存也称之为“会话缓存”,它是基于SqlSession的,默认是开启的,且无法关闭,当使用同一个Mapper、执行同样的查询、传递的是同样的参数时,后续的查询将直接返回前序的查询结果。
一级缓存的结果会因为手动清除(调用SqlSession对象的clearCache()方法)而消失,也会因为此Mapper执行了任何写操作(增、删、改)而自动清除,无论这个写操作是否改变了任何数据!
关于一级缓存的示例:
@Autowired SqlSessionFactory sqlSessionFactory;
@Test void l1Cache() { SqlSession sqlSession = sqlSessionFactory.openSession(); AlbumMapper albumMapper = sqlSession.getMapper(AlbumMapper.class);
System.out.println("准备执行第1次查询……");
Object queryResult1 = albumMapper.getStandardById(1L);
System.out.println("第1次查询结束!");
System.out.println(queryResult1);
System.out.println("准备执行第2次查询……");
Object queryResult2 = albumMapper.getStandardById(1L);
System.out.println("第2次查询结束!");
System.out.println(queryResult2);
// 清除此前的缓存结果
// sqlSession.clearCache();
albumMapper.deleteById(13000000L);
System.out.println("准备执行第3次查询……");
Object queryResult3 = albumMapper.getStandardById(1L);
System.out.println("第3次查询结束!");
System.out.println(queryResult3);
System.out.println("准备执行第4次查询……");
Object queryResult4 = albumMapper.getStandardById(2L);
System.out.println("第4次查询结束!");
System.out.println(queryResult4);
System.out.println("准备执行第5次查询……");
Object queryResult5 = albumMapper.getStandardById(1L);
System.out.println("第5次查询结束!");
System.out.println(queryResult5);
}
二级缓存也称之为“namespace缓存”,是基于namespace的(其实就是配置SQL的XML对应的Mapper),在Spring Boot中,默认全局开启,但各namespace默认并未开启,可以在XML文件中添加标签以开启当前XML对应的Mapper的二级缓存,只要是同样的查询,且传入的参数相同,后续的查询就可以直接使用前序的查询结果。
二级缓存也会因为调用了此XML中的任何写数据的操作而清除!
注意:二级缓存还可以通过在标签上配置useCache属性来开启或关闭,默认取值为true。 注意:当使用二级缓存后,查询结果的类型必须实现Serializable接口,如果没有实现,在查询时会抛出NotSerializableException异常! 关于MyBatis的#{}和{}格式的占位符 在使用MyBatis时,配置SQL语句中的参数可以使用#{}或{}格式的占位符。 提示:在SQL语句中,所有值都需要使用一对单引号框住,使得数据库在执行时知道这是一个值!只要没有被正确识别为“值”,数据库就会认为这是一个字段名(或列名),由于数字值、布尔值不可能作为字段名,所以,这种值可以不使用单引号框住!例如: 如果在用$时,不用单引号,则需要在传过来的值上加单引号: 提示:当需要执行某个SQL语句时,数据库收到SQL语句后,会先执行词法分析,再执行语义分析,再执行编译,最后再执行! 当使用#{}格式的占位符时,会使用预编译的处理方式,这种处理方式会先使用问号对值进行占位,在值还没有代入之前就进行编译,即在执行之前已经完成了词法分析、语义分析、编译,其中,语义分析过程就已经确定了这条SQL语句的“意思”,最终将值代入执行时,无论这是什么样的值,都不会被误以为是字段名或列名!所以,在使用#{}格式的占位符表示任何值时,都不需要使用一对单引号框住!同时,由于是预编译的,所以,使用#{}格式的占位符时,不会出现SQL注入的问题!注意,使用#{}格式的占位符只能表示某个值! 当使用{}格式的占位符时,会先将值代入到原SQL语句,然后执行编译过程,然后执行,由于在执行语义分析之前就已经将值代入,那么,如果字符串值没有添加一对单引号,就会被误以为是字段名或列名!所以,在使用{}格式的占位符表示字符串值时,需要使用一对单引号框住!同时,由于不是预编译的,所以,代入的值可能改变SQL语句原本的语义,则存在SQL注入风险!注意,使用${}格式的占位符可以表示SQL语句的任何片段,只需要保证将值代入后是合法的语句即可,则整体设计可以更加灵活,但需考虑语法格式的问题和SQL注入风险!