本帖最后由 Mylo 于 2019-7-11 16:33 编辑
MyBatis应用分析与最佳实践A. 传统 JDBC 问题的解决jdbcTemplate.query(sql, new BaseRowMapper(Employee. class));B. ORMHibernate 是一个 ORM 框架
它解决了创建连接,释放资源的重复代码问题 解决了 ResultSet 的映射代码问题 提供了查询缓存 解决了写 SQL 的问题
Hibernate 缺点
每次操作都是表的所有字段,无法做到制定部分字段 自动生成的 SQL 很难进行优化 不支持动态 SQL
MyBatis
解决了 ResultSet 问题 解决了 SQL 硬编码问题
MyBatis 特性
使用连接池对连接进行管理 SQL 和代码分离,集中管理 参数映射和动态 SQL 结果集映射 缓存管理 重复 SQL 提取 插件机制
核心对象
SqlSessionFactoryBuilder
SqlSessionFactory(单例)
SqlSession
Mapper
C. MyBatis 配置文件(mybatis-config.xml)根标签 <configuration>
<properties>
<settings>
<typeAliases>
==<typeHandlers>==
==<objectFactory>==
<plugins>
插件可以拦截 MyBatis 四大对象
Ececutor ParameterHandler ResultHandler StatementHandler
<environments>
<mappers>
<?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>
<properties resource="db.properties"/>
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 控制全局缓存(二级缓存)-->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖-->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
<setting name="proxyFactory" value="CGLIB" />
<!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
<setting name="localCacheScope" value="STATEMENT"/>
<setting name="localCacheScope" value="SESSION"/>
</settings>
<typeAliases>
<typeAlias alias="blog" type="com.gupaoedu.domain.Blog"/>
</typeAliases>
<typeHandlers>
<typeHandler handler="com.gupaoedu.type.MyTypeHandler"></typeHandler>
</typeHandlers>
<!-- 对象工厂 -->
<objectFactory type="com.gupaoedu.objectfactory.GPObjectFactory">
<property name="gupao" value="666"/>
</objectFactory>
<plugins>
<plugin interceptor="com.gupaoedu.interceptor.SQLInterceptor">
<property name="gupao" value="betterme"/>
</plugin>
<plugin interceptor="com.gupaoedu.interceptor.MyPageInterceptor">
</plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 单独使用时配置成MANAGED没有事务 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="BlogMapper.xml"/>
<mapper resource="BlogMapperExt.xml"/>
</mappers>
</configuration>public class MyTypeHandler extends BaseTypeHandler<String> {
public vo id setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
"设置 String 类型的参数的时候调用,Java 类型到 JDBC 类型"
System. out .println(" " --------------- setNonNullParameter1 :" "+parameter);
ps.setString(i, parameter);
}
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
"根据列名获取 String 类型的参数的时候调用,JDBC 类型到 java 类型"
System. out .println(" " --------------- getNullableResult1 :" "+columnName);
return rs.getString(columnName);
}
"后面2个方法不用"
}<typeHandlers>
<typeHandler handler ="com.gupaoedu.type.MyTypeHandler"></ typeHandler>
</typeHandlers><insert id="insertBlog" parameterType="com.gupaoedu.domain.Blog">
insert into blog (bid, name, author_id)
values (#{bid,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR,typeHandler=com.gupaoedu.type.MyTypeHandler},
#{authorId,jdbcType=INTEGER})
</insert><result column="name" property="name" jdbcType="VARCHAR" typeHandler="com.gupaoedu.type.MyTypeHandler"/>D. 动态 SQL 配置<if>
<choose>(<when>,<otherwise>)
<trim>(<where>,<set>)
<foreach><select id ="selectDept" parameterType ="int" resultType ="com.gupaoedu.crud.bean.Department">
select * from tbl_dept where 1 = 1
<if test="deptId != null">
and dept_id = #{deptId, jdbcType=INTEGER}
</if>
</select><select id="getEmpList_choose" resultMap="empResultMap" parameterType="com.gupaoedu.crud.bean.Employee"> SELECT * FROM tbl_emp e <where> <choose> <when test="empId !=null"> e.emp_id = #{emp_id, jdbcType=INTEGER} </when> <when test="empName != null and empName != ''"> AND e.emp_name LIKE CONCAT(CONCAT('%', #{emp_name, jdbcType=VARCHAR}),'%') </when> <when test="email != null "> AND e.email = #{email, jdbcType=VARCHAR} </when> <otherwise> </otherwise> </choose> </where></select><update id ="updateB yPrimaryKeySelective" parameterType ="com.gupaoedu.crud.bean.Employee"> update tbl_emp <set> <if test ="empName != null"> emp_name = #{empName,jdbcType=VARCHAR}, </if> <if test ="gender != null"> gender = #{gender,jdbcType=CHAR}, </if> <if test ="email != null"> email = #{email,jdbcType=VARCHAR}, </if> <if test ="dId != null"> d_id = #{dId,jdbcType=INTEGER}, </if> </set> where emp_id = #{empId,jdbcType=INTEGER}</update><insert id ="insertSelective" parameterType="com.gupaoedu.crud.bean.Employee"> insert into tbl_emp <trim prefix ="("suffix=")" suffixOverrides=","> <if test="empId != null"> emp_id, </if> <if test ="empName != null"> emp_name, </if> <if test ="dId != null"> d_id, </if> </trim> <trim prefix="values("suffix=")" suffixOverrides=","> <if test="empId != null"> #{empId,jdbcType=INTEGER}, </if> <if test ="empName != null"> #{empName,jdbcType=VARCHAR}, </if> <if test ="dId != null"> #{dId,jdbcType=INTEGER}, </if> </trim></insert>E. 批量操作<!-- 批量插入 --><insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true"> <selectKey resultType="long" keyProperty="id" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> insert into tbl_emp(emp_id, emp_name, gender,email, d_id) values <foreach collection="list" item="emps" index="index" separator=","> (#{emps.empId},#{emps.empName},#{emps.gender},#{emps.email},#{emps.dId}) </foreach></insert>Batch Executor
定义一个批量操作的执行器 在 <settings> 标签里设置
SIMPLE(默认) REUSE BATCH(批处理)
也可以在创建会话的时候指定
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);F. 嵌套(关联)查询 / N + 1 / 延时加载<select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap"> select b.bid, b.name, b.author_id, a.author_id , a.author_name from blog b left join author a on b.author_id=a.author_id where b.bid = #{bid, jdbcType=INTEGER}</select> <resultMap id="BlogWithAuthorResultMap" type="com.gupaoedu.domain.associate.BlogAndAuthor"> <id column="bid" property="bid" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <!-- 联合查询,将author的属性映射到ResultMap --> <association property="author" javaType="com.gupaoedu.domain.Author"> <id column="author_id" property="authorId"/> <result column="author_name" property="authorName"/> </association></resultMap><select id="selectBlogWithAuthorQuery" resultMap="BlogWithAuthorQueryMap"> select b.bid, b.name, b.author_id, a.author_id , a.author_name from blog b left join author a on b.author_id=a.author_id where b.bid = #{bid, jdbcType=INTEGER}</select><!-- 另一种联合查询(一对一)的实现,但是这种方式有“N+1”的问题 --><resultMap id="BlogWithAuthorQueryMap" type="com.gupaoedu.domain.associate.BlogAndAuthor"> <id column="bid" property="bid" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <association property="author" javaType="com.gupaoedu.domain.Author" column="author_id" select="selectAuthor"/></resultMap><select id="selectAuthor" parameterType="int" resultType="com.gupaoedu.domain.Author"> select author_id authorId, author_name authorName from author where author_id = #{authorId}</select><!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false --><setting name="lazyLoadingEnabled" value="true"/><!--当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过 select 标签的 fetchType 来覆盖--><setting name="aggressiveLazyLoading" value="false"/><!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认 JAVASSIST --><setting name="proxyFactory" value="CGLIB"/>G. 翻页逻辑翻页与物理翻页的区别
逻辑翻页的支持:RowBounds
物理翻页的几种实现方式
H. 配置太多I. 通用 MapperJ. MyBatis-Plus
|
|