mapper配置
标签介绍
insert,update,delete,select,sql,resultMap
sql:可被其它语句引用的可重用语句块;resultMap:确定实体类属性与表中字段对应关系;
namespace的作用
在MyBatis中,Mapper中的namespace用于绑定Dao接口的,即面向接口编程。
它的好处在于当使用了namespace之后就可以不用写接口实现类,业务逻辑会直接通过这个绑定寻找到相对应的SQL语句进行对应的数据处理
parametetType属性
在insert,update,select,delete标签中,可以通过parameterType指定输入参数的类型,类型可以是简单类型、map、pojo的包装类型。
parameterType属性是可以省略的.MyBatis框架可以根据SqlSession接口中方法的参数来判断输入参数的实际数据类型.
#{}和${}区别
在MyBatis中提供了两种方式读取参数的内容到SQL语句中,分别是
1 | #{参数名} :实体类对象或则Map集合读取内容,采用预编译方式,可以防止SQL注入 |
在大多数情况下,我们都是采用#{}读取参数内容,但是在一些特殊的情况下:表名、选取的列是动态的,order by和in操作,可以考虑使用${}。
resultType属性
- resultType属性存在select标签.负责将查询结果进行映射.
- resultType属性可以指定一个基本类型也可以是一个实体类类型
- 使用resultType属性为实体类类型时,只有查询出来的列名和实体类中的属性名一致,才可以映射成功. 如果查询出来的列名和pojo中的属性名全部不一致,就不会创建实体类对象.但是只要查询出来的列名和实体类中的属性有一个一致,就会创建实体类对象
- resultType属性无法与resultMap属性同时出现.
注解方式配置
注解方式就是将SQL语句直接写在接口上,对于需求比较简单的系统,效率较高。缺点在于,每次修改sql语句都要编译代码,对于复杂的sql语句可编辑性和可读性都差,一般不建议使用这种配置方式。
1 | @Select |
typeAliases 别名
全局配置mybatis.xml 文件中
MyBatis事务
在 mybatis 中默认是关闭了 JDBC 的自动提交功能setAutoCommit(false)。
每一个 SqlSession 默认都是不自动提交事务,需要使用session.commit()提交事务。或者使用openSession(true);全局设置自动提交,相当于setAutoCommittrue);
在 openSession()时 Mybatis 会创建 SqlSession 时同时创建一个Transaction(事务对象),同时 autoCommit 都为 false。如果出现异常,应该 session.rollback()回滚事务。
mybatis 中
1 | <insert id="insertUser" parameterType="User"> |
Java:
1 | //插入数据 |
动态SQL
根据不同的条件需要执行不同的 SQL 命令.称为动态 SQL,MyBatis 中动态 SQL 在 mapper.xml 中添加逻辑判断。
<if>
例子:
1 | <select id="getAllUser" resultType="user"> |
<where>
此时where不好处理,还要加一个1=1,因此引入where标签。当编写 where 标签时,如果内容中第一个是 and 去掉第 一个and, 如果<where>中有内容会生成 where 关键字,如果没有内容不生成 where 关键字。
1 | <select id="getAllUser" resultType="user"> |
<choose><when> <otherwise>
有时我们不想应用所有的条件, 相反我们想选择很多情况下的一种。 Java 中的 switch 和语句相似,MyBatis 提供 choose 元素
只要有一个成立其他都不成立。
1 | <select id="getAllUser" resultType="user"> |
<set>
用在修改 SQL 中 set 从句。用来去掉最后一个逗号。如果<set>里面有内容生成 set 关键字,没有就不生成。
例:
1 | <update id="updateUserByid"> |
接口:
1 | public int updateUserByid(@Param("id")Integer id, @Param("name")String name); |
结果:
<Trim>
标签属性:
1 | prefix 在前面添加内容 |
1 | <update id="upd" parameterType="User"> |
得到sql语句就是:update user set name=? where id=?
<bind>
给参数重新赋值,比如在原内容前后添加内容,如:模糊查询。
1 | <select id="selByUserNameLike" resultType="user"> |
1 | public List<User> selByUserNameLike(@Param("name")String name); |
<foreach>
循环参数内容,还具备在内容的前后添加内容,还具备添加分隔符功能。 适用场景:in 查询中,批量新增中(mybatis 中foreach 效率比较低)
1 | <select id="selIn" parameterType="list" resultType="user"> |
接口:
public List
测试:
1 | List<String> list = new ArrayList<>(); |
结果:
插入集合数据
1 | <insert id="insertList" parameterType="list"> |
接口:
public int insertList(@Param(“list”)List<?> list);
测试:
1 | List<String> list = new ArrayList<>(); |
结果:
如果是批量插入数据,应该这样处理。
创建session时,openSession()必须指定参数。 底层 JDBC 的 PreparedStatement.addBatch();
factory.openSession(ExecutorType.BATCH)
<sql> <include>
某些 SQL 片段如果希望复用,可以使用<sql>定义这个片段,在<select>或<delete>或<update>或<insert>中使用<include>
Mybatis 注解
Mybatis 的注解简化 mapper.xml 文件,如果涉及动态 SQL 依然使用 mapper.xml,mapper.xml 和注解可以共存,使用注解时 mybatis.xml 中<mappers>使用
1 | <package/> |
1 | public interface StudentTeacher { |
使用注解实现resultMap:
1 | /** |
1 | @Results() 相当于<resultMap> |
缓存
一级缓存
基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 SqlSession ,当 Session flush 或 close 之后,该Session中的所有 ache 就将清空。缓存的是statement,刷新缓存是清空这个 SqlSession 的所有缓存, 不单单是某个键。任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的。同一个session多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存,以后直接先从缓存中取出数据,不会直接去查数据库。
1 | public static void main(String[] args) throws IOException { |
同一个session,结果只查一次数据库。结果如下:
二级缓存
二级缓存又叫SQLSessionFactory缓存,二级缓存存在于 SqlSessionFactory 生命周期中。二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源Ehcache。
对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。当 SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存的数据刷(flush)到 SqlSessionFactory 缓存区中。
有效范围:同一个 factory 内所有SqlSession 都可以获取。二级缓存在数据频繁被使用,很少被修改时使用性能最高。
使用二级缓存步骤:在 mapper.xml 中添加<cache readOnly=”true”></cache> 如果不写 readOnly=”true”需要把实体类序列化,示例:
1 | public static void main(String[] args) throws IOException { |
说明:可以在开启二级缓存时候,手动配置一些属性
1 | <cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/> |
各个属性意义如下:
1 | eviction:缓存回收策略 |
可以在Mapper的具体方法下设置对二级缓存的访问:useCache配置, 如果一条语句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如:
1 | <select id="selectAll" resultMap="BaseResultMap" useCache="false"> |
刷新缓存(清空缓存)
二级缓存默认会在insert、update、delete操作后刷新缓存,可以手动配置不更新缓存,如下:
1 | <update id="updateById" parameterType="User" flushCache="false" /> |
如果不做任何处理,都为默认配置,则结果如下:
* 1. 映射语句文件中的所有select语句将会被缓存。
* 2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。
* 3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。
* 4. 缓存会根据指定的时间间隔来刷新。
* 5. 缓存会存储1024个对象
自定义缓存
自定义缓存对象,该对象必须实现 org.apache.ibatis.cache.Cache 接口,如下:
1 | public class CacheTest implements Cache { |
配置:
1 | <cache readOnly="true" type="com.hu.test.CacheTest"></cache> |
测试:
1 | public static void main(String[] args) { |
每次查询数据库前,MyBatis都会先在缓存中查找是否有该缓存对象。只有当调用了commit() 方法,MyBatis才会往缓存中写入数据,数据记录的键为 数字编号+Mapper名+方法名+SQL语句+参数 格式,值为返回的对象值。