Mybatis

快速开始

public interface UserDao {    List<User> findAll();}
<?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>    <environments default="development">        <environment id="development">            <!--事务类型-->            <transactionManager type="JDBC"/>            <!--连接池-->            <dataSource type="POOLED">                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>                <property name="url" value="jdbc:mysql:///mybatis"/>                <property name="username" value="root"/>                <property name="password" value="123"/>            </dataSource>        </environment>    </environments>    <mappers>        <mapper resource="mappers/user.xml"/>    </mappers></configuration>
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="wang.ismy.mybatis.dao.UserDao">    <select id="findAll" resultType="wang.ismy.mybatis.entity.User">    SELECT * FROM user  </select></mapper>

使用xml

@Testpublic void findAll() throws IOException {    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(            Resources.getResourceAsStream("config.xml"));    SqlSession sqlSession = factory.openSession();    List<User> list = sqlSession.getMapper(UserDao.class).findAll();    assertEquals(6,list.size());}

根据条件查询

<select id="findById" resultType="wang.ismy.mybatis.entity.User">        SELECT * FROM user WHERE id = #{id}    </select>

细节:

更新

<insert id="save" parameterType="wang.ismy.mybatis.entity.User">    INSERT INTO user(username,address,sex,birthday)     VALUES(#{username},#{address},#{sex},#{birthday})</insert>
int save(User user);

需要注意的是,mybatis的SqlSession关闭了事务的默认提交,当进行完更新操作后,需要手动调用sqlSession.commit();

模糊查询字符串拼接问题

SELECT * FROM user WHERE username LIKE '%' #{name} '%'

插入数据后返回ID

<insert id="save" parameterType="wang.ismy.mybatis.entity.User">    <selectKey keyColumn="id" keyProperty="id" resultType="int">    select last_insert_id();    </selectKey>    INSERT INTO user(username,address,sex,birthday) VALUES(#{username},#{address},#{sex},#{birthday})</insert>

使用resultMap

<resultMap id="userMap" type="wang.ismy.mybatis.entity.User">    <!--主键-->    <id column="id" property="id"/>    <!--非主键-->    <result column="username" property="username"/></resultMap><select id="findAll" resultMap="userMap">    select * from user</select>

Properties标签

<properties resource="jdbc.cfg">    </properties>

typeAliases标签

<typeAliases>    <!--指定别名,不区分大小写-->    <typeAlias type="wang.ismy.mybatis.entity.User" alias="user"/>    <!--指定该包下的所有类为别名,不区分大小写-->    <package name="wang.ismy.mybatis.entity"/></typeAliases>

mapper

<mappers>    <package name="wang.ismy.mybatis.dao"></mappers>

使用注解

public interface UserDao {    @Select("SELECT * FROM user")    List<User> findAll();}
注解作用
@Insert实现新增
@Update实现更新
@Delete实现删除
@Select实现查询
@Result实现结果集封装
@Results可以与@Result 一起使用,封装多个结果集
@ResultMap实现引用@Results 定义的封装
@One实现一对一结果集封装
@Many实现一对多结果集封装
@SelectProvider实现动态 SQL 映射
@CacheNamespace实现注解二级缓存的使用

Result注解使用

@Select("SELECT * FROM user")@Results({        @Result(id=true,column = "id",property ="id"),        @Result(column = "username",property ="username"),        @Result(column = "sex",property ="sex"),        @Result(column = "address",property ="address"),        @Result(column = "birthday",property ="birthday")})List<User> find();
一对一查询
@Select("SELECT * FROM account")@Results({        @Result(id=true,column = "id",property = "id"),        @Result(column = "uid",property = "uid"),        @Result(column = "money",property = "money"),        @Result(column = "uid",property = "user",one = @One(select = "wang.ismy.mybatis.dao.UserDao.findById",fetchType = FetchType.LAZY))})List<Account> findAll();

一对多查询

@Select("SELECT * FROM user")@Results({        @Result(id=true,column = "id",property ="id"),        @Result(column = "username",property ="username"),        @Result(column = "sex",property ="sex"),        @Result(column = "address",property ="address"),        @Result(column = "birthday",property ="birthday"),        @Result(column = "id",property = "account",                many = @Many(select = "wang.ismy.mybatis.dao.AccountDao.findById",fetchType = FetchType.LAZY))})List<User> find();

开启二级缓存

@CacheNamespacepublic interface UserDao {}
<!--如果使用注解的话,则指定class属性--><mappers>    <mapper class="wang.ismy.mybatis.dao.UserDao"/></mappers>

原理及源码分析

自定义Mybatis分析

Mapper 注册中心 -> 执行器 -> StatementHadnler -> ResultsetHandler

核心接口:

XML相关:

重点:

MapperProxy:

MapperMethod

ParamNameResolver

MappedStatement

Executor

StatementHandler

MetaObject:拦截器元数据

缓存机制

延迟加载

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

<settings>    <setting name="logImpl" value="STDOUT_LOGGING" />    <!--延迟加载相关-->    <setting name="lazyLoadingEnabled" value="true"/>    <setting name="aggressiveLazyLoading" value="false"/></settings>
<resultMap id="userMap" type="user">    <id column="id" property="id"/>    <result column="username" property="username"/>    <result property="address" column="address"/>    <result property="birthday" column="birthday"/>    <result property="sex" column="sex"/>    <collection property="account" ofType="Account" select="wang.ismy.mybatis.dao.AccountDao.findById" column="id">        <id column="account_id" property="id"/>        <result column="uid" property="uid"/>        <result column="money" property="money"/>    </collection></resultMap>

使用的动态代理实现的延迟加载

缓存

批注 2020-05-18 103307

一级缓存

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

命中原则:

生命周期:

缓存销毁:

设计理念:

二级缓存

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

二级缓存中存放的是数据而不是对象

开启
<!--默认为true,可以省略--><setting name="cacheEnabled" value="true"/>
<cache/>
<select id="findAll" resultMap="userMap" useCache="true">    SELECT * FROM user</select>
命中原则
生命周期

创建:

销毁:

缓存清除策略

批注 2020-05-18 105408

多表查询

一对一

<resultMap id="accountMap" type="Account">    <id column="account_id" property="id"/>    <result column="UID" property="uid"/>    <result column="MONEY" property="money"/>    <association property="user" javaType="User">        <id column="id" property="id"/>        <result column="username" property="username"/>        <result property="address" column="address"/>        <result property="birthday" column="birthday"/>        <result property="sex" column="sex"/>    </association></resultMap>
<select id="findAll" resultMap="accountMap">     SELECT account.ID AS account_id,     account.UID,     account.MONEY,     user.*     FROM account,user     WHERE account.UID = user.id</select>
@Datapublic class Account {    private Integer id;    private Integer uid;    private Double money;    private User user;}

一对多

<resultMap id="userMap" type="user">    <id column="id" property="id"/>    <result column="username" property="username"/>    <result property="address" column="address"/>    <result property="birthday" column="birthday"/>    <result property="sex" column="sex"/>    <collection property="account" ofType="Account">        <id column="account_id" property="id"/>        <result column="uid" property="uid"/>        <result column="money" property="money"/>    </collection></resultMap><select id="findAll" resultMap="userMap">   SELECT user.*,    account.ID as account_id,    account.uid,    account.money    FROM user LEFT OUTER JOIN account ON user.id = account.UID</select>
@Datapublic class User {    private Integer id;    private String username;    private LocalDate birthday;    private String sex;    private String address;    private List<Account> account;}

左外连接的使用

多对多

多对多的映射关系,可以拆分成两个一对多的关系

动态SQL

if

<if test="username != null">    #{username} 'abc'</if>

where 标签

<where>    <if test="...">        ...    </if></where>

这样就不用写where 1=1前缀

foreach标签

<foreach collection="ids" open="id in ( " close=")" item="uid"  separator=",">      #{uid}     </foreach>

SQL重用

<sql id="sql">    SELECT * FROM user WHERE id = #{id}</sql><select id="findById" resultType="wang.ismy.mybatis.entity.User">    <include refid="sql"/></select>

连接池与事务

连接池:

事务:

/*提交事务*/sqlSession.commit();/*回滚事务*/sqlSession.rollback();

分页插件

<dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>5.1.10</version></dependency>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    <property name="dataSource" ref="dataSource" />    <property name="plugins">        <array>            <bean class="com.github.pagehelper.PageInterceptor">                <property name="properties">                    <props>                        <prop key="helperDialect">oracle</prop>                        <prop key="reasonable">true</prop>                                            </props>                </property>            </bean>        </array>    </property></bean>
@Overridepublic List<Order> findAll() {    PageHelper.startPage(1,5);    return orderDao.findAll();}