01、MyBatis的核心对象
Mapper(实际上是一个代理对象)是从SqlSession中获取的。它的作用是发送SQL来操作数据库的数据。它应该在一个SqlSession事务方法之内。
02、核心代码的简单调用
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = (Blog) session.selectOne("com.mybatis.mapper.BlogMapper.selectBlogById", 1);
System.out.println(blog);
} finally {
session.close();
}
03、MyBatis核心配置
【1】、configuration
整个配置文件的根标签,对应的Configuration类,
【2】、properties
用来配置参数信息,比如最常见的数据库连接信息。在xml配置文件中用${}引用。
【3】、settings
setttings里面是MyBatis的一些核心配置
<?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"></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>
</configuration>
【4】、typeAliases
类型的别名。比如我们的参数类型和返回值类型都可能会用到我们的Bean,比如com.mybatis.domain.Blog都只要写blog就可以了。
【5】、typeHandlers【重点】
自定义Java类型和数据库的JDBC类型的相互转换规则。
说明:
1、类型处理器接口:TypeHandler
定义类型处理器的基本作用:从Java类型到JDBC类型和从JDBC类型到Java类型
2、类型引用:TypeReference
用于获取Java中的原生类型,即byte、short、int、long、float、double、boolean、char八大基本数据类型。为了持有这个具体的类型处理器所处理的Java类型的原生类型。
3、基础类型处理器:BaseTypeHandler
内部简单的实现了TypeHandler接口中定义的四个方法中实现了所有类型处理器公共部分
4、案例
public class MyTypeHandler extends BaseTypeHandler<String> {
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
// 设置 String 类型的参数的时候调用,Java类型到JDBC类型
// 注意只有在字段上添加typeHandler属性才会生效
// insertBlog name字段
System.out.println("---------------setNonNullParameter1:"+parameter);
ps.setString(i, parameter);
}
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 根据列名获取 String 类型的参数的时候调用,JDBC类型到java类型
// 注意只有在字段上添加typeHandler属性才会生效
System.out.println("---------------getNullableResult1:"+columnName);
return rs.getString(columnName);
}
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
// 根据下标获取 String 类型的参数的时候调用
System.out.println("---------------getNullableResult2:"+columnIndex);
return rs.getString(columnIndex);
}
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
System.out.println("---------------getNullableResult3:");
return cs.getString(columnIndex);
}
}
【6】、plugins
插件。MyBatis预留了插件的接口,让MyBatis更容易扩展。
插件可以拦截这四个对象的这些方法,其中4个对象为MyBatis的四大对象。
Executor、ParameterHandler、ResultSetHandler、StatementHandler。
【7】、environments、environment
environments标签用来管理数据库的环境。
一个environment标签就是一个数据源,代表一个数据库。
如:
<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>
【8】、transactionManager
配置事务
JDBC:使用Connection对象的commit()、rollback()、close()管理事务。
MANAGED:把事务交给容器来管理,比如JBOSS,Weblogic。
【9】、dataSource
数据源
【10】、mappers
映射器:Mapper.xml的路径。作用是让MyBatis在启动的时候去扫描这些映射器,创建映射关系。
总结:
Mybatis九大类全局配置节点按照如下顺序排序,位置不能颠倒。
properties=>settings=>typeAliases=>typeHandlers=>objectFactory=>plugins=>environment=>databaseIdProvider=>mappers
【11】、settings
设置MyBatis的一些最关键的配置
04、Mapper.xml映射配置文件【重点】
映射器里面最主要的是配置了SQL语句,也解决了我们的参数映射和结果集映射的问题。
8个标签
cache : 该命名空间的缓存配置
cache-ref : 引用其它命名空间的缓存配置。
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
<resultMap id="BaseResultMap" type="blog">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="author_id" property="authorId" jdbcType="INTEGER"/>
</resultMap>
sql : 可被其它语句引用的可重用语句块。
<sql id="Base_Column_List">
bid, name, author_id
</sql>
insert :映射插入语句
update : 映射更新语句
delete : 映射删除语句
select : 映射查询语句
05、动态SQL
MyBaits的动态SQL基于OGNL表达。
【1】、if:需要判断的时候,条件写在test中
<select id="selectByExample" parameterType="com.BlogExample" resultMap="BaseResultMap">
select
*
from blog
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null AND parameter != null">
order by ${orderByClause}
</if>
</select>
【2】、choose(when,otherwise):需要选择一个条件的时候
<select id="getEmpList_choose" resultMap="empResultMap" parameterType="com.Employee">
SELECT * FROMtbl_emp e
<where>
<choose>
<when test="emp_id!=null">
e.emp_id=#{emp_id,jdbcType=INTEGER}
</when>
<when test="emp_name!=null">
AND e.emp_nameLIKE CONCAT(CONCAT('%',#{emp_name,jdbcType=VARCHAR}),'%')
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
【3】、trim(where,set):需要去掉where、and、逗号之类的符号的时候。
<update id="updateByPrimaryKeySelective" parameterType="com.Employee">
update tbl_emp
<set>
<if test="empName!=null">
emp_name=#{empName,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.Employee">
insert into tbl_emp
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="empName!=null">
emp_name,
</if>
<if test="dId!=null">
d_id,
</if>
</trim>
<trim prefix="values(" suffix=")" suffixOverrides=",">
<if test="empName!=null">
#{empName,jdbcType=VARCHAR},
</if>
<if test="dId!=null">
#{dId,jdbcType=INTEGER},
</if>
</trim>
</insert>
【4】、foreach:需要遍历集合的时候
<delete id="deleteByList"parameterType="java.util.List">
delete from tbl_emp where emp_idin
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.empId,jdbcType=VARCHAR}
</foreach>
</delete>
06、批量插入
MyBatis的动态标签的批量操作也是存在一定的缺点的,比如数据量特别大的时候,拼接出来的SQL语句过大。
MySQL的服务端对于接收的数据包有大小限制,max_allowed_packet默认是4M,需要修改默认配置才可以解决这个问题。
当然:在我们的全局配置文件中,可以配置默认的Executor的类型。其中有一种BatchExecutor。
<setting name="defaultExecutorType" value="BATCH"/>
也可以在创建会话的时候指定执行器类型:
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
案例:
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true">
insert into tbl_emp(emp_id,emp_name)
values
<foreach collection="list" item="emps" index="index" separator=",">
(#{emps.empId},#{emps.empName})
</foreach>
</insert>
07、嵌套(关联)查询/N+1/延迟加载
【1】、resultType和resultMap的区别
resultMap功能更强大,可以通过设置typeHander来自定义实现功能。
【2】、一对一的关联查询有两种配置方式
1、嵌套结果
<!-- 根据文章查询作者,一对一查询的结果,嵌套查询 -->
<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>
2、嵌套查询
<!-- 另一种联合查询(一对一)的实现,但是这种方式有“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"/> <!-- 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>
08、翻页
PageHelper分页插件
原理拦截器,主要拦截Executor对象中的query(MappedStatement ms,Object o,RowBounds ob ResultHandler rh)这个方法。
09、mybatis-plus
参考:https://www.jianshu.com/p/ceb1df475021
10、PreparedStatement和statement的区别
.【1】、PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程
【2】、使用 Statement 对象。在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。
【3】、statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement是预编译得, preparedstatement支持批处理