mybatis 总结


mybatis
半自动 orm 框架,三要素,SQL,映射规则 和 POJO

核心类
SqlSessionFactoryBuilder 读取配置信息创建 SqlSessionFactory,建造者模式
SqlSessionFactory 创建 Sqlsession,工厂单例模式,存在于程序的整个生命周期
SqlSession 代表一次数据库连接,一般通过调用 Mapper 访问数据库,也可以直接发送 SQL 执行
SQL Mapper 由一个 Java 接口和 XML 文件组成,包含了要执行的 SQL 语句和结果集映射规则
--------------------------------------------------------
将 sql 查询出来的字段值 映射成 pojo 对象,有两种方式:resultType 和 resultMap
--------------------------------------------------------
resultType
SQL 语句查询出的字段 在相应的 pojo 中必须有和它相同的字段对应,
而 resultType 中的内容就是 pojo 在本项目中的位置

自动映射注意事项
SQL 列名和 JavaBean 的属性是一致的
使用 resultType,如用简写需要配置 typeAliases (别名)
如果列名和 JavaBean 不一致,但列名符合单词下划线分割,Java 是驼峰命名法,
则 mapUnderscoreToCamelCase 可设置为 true
--------------------------------------------------------
resultMap
使用场景
字段有自定义的转化规则
复杂的多表查询
--------------------------------------------------------
到底应该用 resultType 还是 resultMap?
resultType 会让 数据库表里的字段名 和 实体类的属性名 耦合
阿里强制使用 resultMap, 即使所有类属性名与数据库字段一一对应,也需要定义
--------------------------------------------------------
mybatis 默认只传一个参数,传多个参数有三种方法
// 第一种方式使用map, 接口看不出参数,可读性差,杜绝使用
Map<String, Object> params = new HashMap<String, Object>();
params.put("email", email);
params.put("sex", sex);
List<TUser> list1 = mapper.selectByEmailAndSex1(params);
xml 映射文件
parameterType="map"
sql 里获取 #{email}

// 第二种方式使用注解,参数少于5个的时候,推荐使用
List<TUser> list2 = mapper.selectByEmailAndSex2(email, sex);
mapper 接口方法参数加注解
List<TUser> selectByEmailAndSex2(@Param("email")String email,@Param("sex")Byte sex);
xml 映射文件
sql 里获取 #{email}
        
// 第三种方式使用 pojo对象,参数大于5个的时候,推荐使用
EmailSexBean esb = new EmailSexBean();
esb.setEmail(email);
esb.setSex(sex);
List<TUser> list3 = mapper.selectByEmailAndSex3(esb);
xml 映射文件
parameterType="com.enjoylearning.mybatis.entity.EmailSexBean"
sql 里获取 #{email}        
--------------------------------------------------------
获取主键
通过 insert / update 标签相关属性
useGeneratedKeys - 默认值 false MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(MySQL / SQL Server 自动递增字段) keyProperty - 默认值 unset 唯一标记一个属性,如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表
MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值
xml映射文件
useGeneratedKeys="true" keyProperty="id"
service 里
user1.getId()
--------------------------------
通过 selectKey 元素
keyProperty - 主键属性 resultType - 接收主键的 java 属性类型
order BEFORE - 首先选择主键,设置 keyProperty 然后执行插入语句,如 oracle
<selectKey keyProperty=“id” order= "Before" resultType="int">
   select SEQ_ID.nextval from dual
</selectKey>
AFTER - 先执行插入语句,然后获取主键字段,如 mysql 
<selectKey keyProperty="id" order="AFTER" resultType="int"> 
    select LAST_INSERT_ID()
</selectKey>
--------------------------------------------------------
SQL 元素 - 用来定义可重用的 SQL 代码段,可以包含在其他语句中
---------------------------
SQL 参数  向 sql 语句中传递的可变参数
预编译 #{} - 将传入的数据都当成一个字符串,会对自动传入的数据加一个单引号,
能够防止 sql 注入
传值 ${} 传入的数据直接在 sql 中替换,无法防止 sql 注入
适用场景 动态报表
表名、选取的列是动态的,order by 和 in 操作,可以考虑使用$ 
--------------------------------------------------------
mybatis 如何实现批量处理
1.通过 foreach 动态拼接语句
2.通过 batch 类型的 excutor
--------------------------------------------------------
MyBatis Generator - MyBatis 的开发团队提供了一个很强大的代码生成器,代码包含了数据库表对应的实体类, Mapper 接口类, Mapper XML 文件等,这些代码文件中几乎包含了全部的单表操作方法
--------------------------------------------------------
关联方式
嵌套结果 
通过联合查询,把关联对象需要的数据一次性查出来
嵌套查询 
先查主表,再查从表
嵌套查询会导致“N+1 查询问题”,导致该问题产生的原因:
1. 你执行了一个单独的 SQL 语句来获取结果列表(就是“+1”)。
2. 对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。 这个问题会导致成百上千的 SQL 语句被执行。这通常不是期望的
解决“N+1 查询问题”的办法就是开启懒加载 
在<select>节点上配置“fetchType=lazy”

在 MyBatis 核心配置文件中加入如下配置
<setting name="aggressiveLazyLoading" value="false" />
--------------------------------------------------------
一对一关联嵌套结果
<resultMap id="userAndPosition1" extends="BaseResultMap" type="TUser">
  <association property="position" javaType="TPosition" columnPrefix="post_">
    <id column="id" property="id"/>
    <result column="name" property="postName"/>
    <result column="note" property="note"/>
  </association>
</resultMap>

<select id="selectUserPosition1" resultMap="userAndPosition1">
  select a.id, user_name, real_name, sex, mobile,
    email, a.note,  
         b.id  post_id, b.post_name, b.note post_note
  from t_user a, t_position b
  where a.position_id = b.id
</select>
--------------------------------------------------------
一对一关联嵌套查询
<select id="selectUserPosition2" resultMap="userAndPosition2">
  select a.id, a.user_name, a.real_name, a.sex,
     a.mobile, a.position_id
  from t_user a
</select>

//# fetchType [ lazy / eager ]
<resultMap id="userAndPosition2" extends="BaseResultMap" type="TUser">
  <association property="position" fetchType="lazy"  column="position_id"      select="package.selectByPrimaryKey" />
</resultMap>
--------------------------------------------------------
一对多关联嵌套结果
<select id="selectUserJobs1" resultMap="userAndJobs1">
  select a.id, a.user_name, a.real_name, a.sex, a.mobile,
     b.comp_name, b.years, b.title
  from t_user a, t_job_history b
  where a.id = b.user_id
</select>

<resultMap id="userAndJobs1" extends="BaseResultMap" type="TUser">
  <collection property="jobs" ofType="package.TJobHistory" >
    <result column="comp_name" property="compName" jdbcType="VARCHAR" />
    <result column="years" property="years" jdbcType="INTEGER" />
    <result column="title" property="title" jdbcType="VARCHAR" />
  </collection>
</resultMap>

private List<TJobHistory> jobs;
--------------------------------------------------------
一对多关联嵌套查询
<select id="selectUserJobs2" resultMap="userAndJobs2">
  select a.id, a.user_name, a.real_name, a.sex, a.mobile
    from t_user a
</select>

<resultMap id="userAndJobs2" extends="BaseResultMap" type="TUser">
  <collection property="jobs" fetchType="lazy" column="id"
    select="package.selectByUserId" />
</resultMap>

private List<TJobHistory> jobs;
--------------------------------------------------------
多对多嵌套结果
<select id="selectUserRole" resultMap="userRoleInfo">
  select a.id, a.user_name, a.real_name, a.sex, a.mobile, a.note,
         b.role_id,
     c.role_name, c.note role_note
  from t_user a, t_user_role b, t_role c
  where a.id = b.user_id AND b.role_id = c.id
</select>

<resultMap type="TUser" id="userRoleInfo" extends="BaseResultMap">
  <collection property="roles" ofType="TRole" columnPrefix="role_">
    <result column="id" property="id" />
    <result column="Name" property="roleName" />
    <result column="note" property="note" />
  </collection>
</resultMap>

private List<TRole> roles;    
--------------------------------------------------------
多对多嵌套查询
--------------------------------------------------------
一级缓存
在 select 标签上配置 flushCache=“true”
true - 关闭
false - 开启,默认
同一个 SqlSession 内,调用相同 Mapper 方法和参数走一级缓存
任何的 INSERT / UPDATE / DELETE 操作都会清空一级缓存
--------------------------------------------------------
二级缓存
也叫应用缓存,生命周期同 SqlSessionFactory,可以跨 sqlSession
缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响
在 MyBatis 的核心配置 文件中 cacheEnabled 参数是二级缓存的全局开关,默认值是 true,
SQL Mapper 文件中配置
<cache eviction=“LRU" flushInterval="60000" size="512" readOnly="true"/>
映射文件中的所有 select 语句将会被缓存
映射文件中的所有 insert / update / delete 会清空缓存
缓存会使用 LRU - 最近最少使用算法来收回
缓存会存储列表集合或对象的 512 个引用
缓存会被视为是 read/write(可读/可写)的缓存

一般不建议使用二级缓存
使用二级缓存容易出现脏读,建议避免使用,在业务层使用 redis 更好

调用过程
1.每次与数据库的连接都会优先从缓存中获取数据
2.先查二级缓存,再查一级缓存
3.二级缓存以 namespace 为单位的,是 SqlSession 共享的,容易出现脏读,建议避免使用
4.一级缓存是 SqlSession 独享的,建议开启

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我三师弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值