Mybatis框架学习

Mybatis介绍

​ MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

Mybatis简单使用

​ 添加依赖

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>
  1. 初始化SqlSessionFactory对象

    每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

    构建对象

    // 1. 初始化mybatis配置
    String confPath = "mybatis_conf.xml";
    InputStream in = Resources.getResourceAsStream(confPath);
    
    // 2. 构建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    

    XML 配置文件中包含了对 MyBatis 系统的核心设置,包含了获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。

    <?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文件,路径从类路径的根目录开始 -->
        <properties resource="jdbc.properties" />
    
        <settings>
            <!-- 开启将数据库中下划线连接的字段自动映射为Java的小驼峰命名 -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <!-- 定义类型别名,在xxxMapper.xml文件中就可以用别名代替很长的类名 -->
        <typeAliases>
            
                <!-- 单个类配置别名 -->
    <!--        <typeAlias type="com.lanou3g.mybatis.bean.User" alias="User" />-->
            
                <!-- 统一配置某个包下所有类的别名, 会使用 Bean 的首字母小写的类名来作为它的别名。 -->
            <package name="com.lanou3g.mybatis.bean" />
        </typeAliases>
    
    
        <!-- 配置不同环境的参数 -->
        <environments default="development">
            <!-- 开发环境数据库、事务配置 -->
            <environment id="development">
                <!-- 事务管理使用JDBC的事务 -->
                <transactionManager type="JDBC"/>
                <!-- 配置开发环境数据源 -->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.user}"/>
                    <property name="password" value="${jdbc.password}"/>
                    <!-- 将所有driver.开头的参数,附加到url属性的值后面上 -->
                    <property name="driver.characterEncoding" value="utf8"/>
                </dataSource>
            </environment>
        </environments>
    
        <!-- 将mapper SQL映射文件包含进来 -->
        <mappers>
            <!-- 将通过XML方式配置的mapper引入进来 -->
            <mapper resource="mapper/userMapper.xml"/>
            <!-- 将通过注解方式配置的mapper引入进来 -->
    <!--        <mapper class="com.lanou3g.mybatis.mapper.UserMapper" />-->
    
            <!-- 将com.lanou3g.mybatis.mapper包下所有通过注解方式配置的mapper引入进来 -->
    <!--        <package name="com.lanou3g.mybatis.mapper"/>-->
        </mappers>
    </configuration>
    
  2. 创建SqlSession对象

    通过上一步的SqlSessionFactory对象可以获取到负责执行SQL语句的SqlSession对象

    // 3.获取SqlSession对象,默认事务不自动提交
    // SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取一个自动提交事务的sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    
  3. 用SqlSession对象从Mybatis中获取Mapper接口的实现类

    // 4. 获取Mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
  4. 编写Mapper对象的xml配置文件

    XML格式的Mapper配置文件类似于接口的实现类,它指定了具体要执行的SQL语句,以及结果集如何映射。

    <?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="com.lanou3g.mybatis.mapper.UserMapper">
        <select id="queryAllUser" resultType="user">
            select * from user
         </select>
    
        <insert id="insertUser">
          insert into user (username,nick_name,email)
          values (#{username},#{nickName},#{email})   //
        </insert>
    </mapper>
    

深入了解Mybatis

主要组件

核心配置文件

核心配置文件是Mybatis的入口,它里面可以配置mybatis的具体参数、数据源、类型别名、关联映射文件等。

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • configuration(配置)

    • properties(属性)

    • settings(设置)

    • typeAliases(类型别名)

    • typeHandlers(类型处理器)

    • objectFactory(对象工厂)

    • plugins(插件)

    • environments(环境配置)

      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)

    • mappers(映射器)

      其具体配置信息详见mybatis官网!https://mybatis.org/mybatis-3/zh/configuration.html#properties

SqlSessionFactory

​ SqlSessionFactory是mybatis的关键对象,它是单个数据库映射关系经过编译后的内存镜像.SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来获得,而SqlSessionFactoryBuilder则可以从配置XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例.SqlSessionFactory是创建SqlSession的工厂.每一个mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心.一个SqlSessionFactory只能连接一个数据库实例,如果需要连接多个数据库,需要构建多个SqlSessionFactory对象。

在构建SqlSesssionFactory时可以指定environment的id,表示使用指定的数据源来构建factory对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in, "dev");
SqlSession

​ SqlSession是mybatis的关键对象,它是执行持久化操作的对象.它是应用程序与持久存储层之间执行交互操作的一个单线程对象,也是mybatis执行持久化操作的关键对象.SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法.

注意: SqlSession对象是非线程安全的,在多线程环境下,建议不要作为类的实例属性来用。

Mapper
  • Mapper接口类

    定义了增删改查的方法。

  • Mapper配置文件

    Mapper配置文件中就是负责实现接口中的方法,它定义了具体要执行什么SQL语句,如何映射结果集。

    • 配置文件中select、delete、update、insert标签的id必须是对应接口中的方法名。
    • mapper文件的namespace属性需要对应Mapper接口的完全类型限定名。

深入Mybatis核心配置文件

​ 同上

深入Mybatis映射配置文件

SQL映射文件常用的元素

​ select 映射查询语句

​ insert 映射插入语句

​ update 映射更新语句

​ delete 映射删除语句

​ cache 给定命名空间的缓存配置

​ cache-ref 其他命名空间缓存配置的引用

​ resultMap 最复杂也是最强大的元素,用来描述如何从数据库结果集中加载对象

select

接口

List<User> queryAllUser();

User queryUserById(Integer id);

xml配置文件

<select id="queryAllUser" resultType="user">
    select * from user
</select>

<select id="queryUserById" resultType="user">
    select * from user where id = #{id}
</select>
insert
普通插入语句

接口

int insertUser(User user);

xml配置文件

<insert id="insertUser">
    insert into user (username,nick_name,email)
    values (#{username},#{nickName},#{email})
</insert>
如何返回数据库自增的ID
<!-- 给insert语句添加useGeneratedKeys、keyProperty后,mybatis会将自增的id值直接赋值到传进来的user对象的id属性上
        useGeneratedKeys: 指定需要获取数据库自增的id
        keyProperty: 指定自增地段的名称
     -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into user (username,nick_name,email)
    values (#{username},#{nickName},#{email})
</insert>
delete

接口

void deleteUserById(Integer id);

XML配置文件

<delete id="deleteUserById">
    delete from user where id = #{id}
</delete>
update

接口

void updateUser(User user);

XML配置文件

<update id="updateUser">
    update user set password = #{password} where id = #{id}
</update>
接口中的参数传递到SQL
简单类型参数

接口

void deleteUserById(Integer id);

xml配置文件

<delete id="deleteUserById">
    delete from user where id = #{id}
</delete>
引用类型参数

接口

int insertUser(User user);

xml配置文件

<!-- 给insert语句添加useGeneratedKeys、keyProperty后,mybatis会将自增的id值直接赋值到传进来的user对象的id属性上  useGeneratedKeys: 指定需要获取数据库自增的id    keyProperty: 指定自增地段的名称-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into user (username,nick_name,email)
    values (#{username},#{nickName},#{email})
</insert>
当接口中参数和XML配置取值时名称不一样时

在接口中的参数前加注解

User queryUserById(@Param("id") Integer xxxxxxxId);

在XML中取值时用注解指定的名称

<select id="queryUserById" resultType="user">
    select * from user where id = #{id}
</select>
结果集如何映射
ResultType方式

ResultType方式适用于数据库结果集可以直接映射成一个Java类的情况

Java实体类:

@Getter
@Setter
@ToString
public class User {
    private Integer id;
    private String username;
    private String nickName;
    private String password;
    private String email;
    private Timestamp lastLoginTime;
}

使用方法:

<select id="queryAllUser" resultType="com.lanou3g.bean.User">
    select * from user
</select>
ResultMap方式

ResultMap方式适用于复杂的结果集映射,比如数据库返回的结果集中的列名和JavaBean无法一一对应,或者对象间存在一对一、一对多关联映射时。

解决数据库列名与Java类中属性名不一致的映射问题
<mapper>
    ...
    <resultMap id="userMap" type="user">
        <id property="id" column="id" />
        <result property="username" column="username" />
        <result property="lastLoginttime" column="last_login_time" />
        <result property="email" column="email" />
        <result property="nickName" column="nick_name" />
    </resultMap>
    ...
</mapper>

在查询语句中将resultType换成resultMap

<select id="queryAllUser" resultMap="userMap">
    select * from user
</selec>
解决一对一映射查询问题

创建实体类

package com.lanou3g.bean;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Girl {
    private Integer id;
    private Integer isQueen;
    private Integer kId;
    private String name;
}

package com.lanou3g.mybatis.bean;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

@Getter
@Setter
@ToString
public class King {
    private Integer id;
    private String name;
    private Queen queen;
    private List<Girl> girls;
}

package com.lanou3g.mybatis.bean;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.Serializable;

@Getter
@Setter
@ToString
public class Queen {
    private Integer id;
    private Integer kId;
    private String name;
}

创建接口

package com.lanou3g.mapping;

import com.lanou3g.bean.King;

public interface KingMapper {

    King findKingById(Integer id);

}

配置核心配置文件(mybatis-confg.xml)

<?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="jdbc.properties"></properties>
    <typeAliases>
        <package name="com.lanou3g.bean"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <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="mapper/KingMapper.xml"></mapper>
    </mappers>

</configuration>

配置mapper文件

<?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="com.lanou3g.mybatis.mapper.KingMapper">
	
    <!--第一种方式-->
    <resultMap id="kingMap" type="king">
        <id column="kid" property="id" />
        <result column="kname" property="name" />
        <!-- 一对一映射关系 -->
        <association property="queen" javaType="queen" resultMap="queenMap" columnPrefix="queen_"/>
    </resultMap>
    
	<!--另外一种方式-->
    <!--<resultMap id="kingMap" type="king">
        <id column="kid" property="id" />
        <result column="kname" property="name" />
        <association property="queen" javaType="queen">
            <id column="qid" property="id" />
            <result column="qname" property="name" />
            <result column="kid" property="kId" />
        </association>
    </resultMap>-->

    <resultMap id="queenMap" type="queen">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="king_id" property="kId" />
    </resultMap>
    
    <!--sql查询语句根据实际情况书写-->
    <select id="findKingById" resultMap="kingMap">
        SELECT
            k.id kid,
            k.`name` kname,
            g. NAME qname,
            g.id gid,
            g.k_id gkid,
            g.is_queen is_queen
        FROM
            king k
        LEFT JOIN girl g ON g.k_id = k.id
        WHERE
            g.is_queen = 1
        AND k.id = #{id};
    </select>
</mapper>
解决一对多映射查询问题

创建实体类、创建接口、配置核心配置文件与上面相同,与一对一映射查询不同的是配置mapper文件,

  • 在一对一映射查询中是用标签,里面指定返回类型用javaType=“具体的类型(最好用全类名)”
  • 在一对多映射查询中用标签,里面指定返回类型用ofType=“具体的类型(最好用全类名)”
<?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="com.lanou3g.mybatis.mapper.KingMapper">

    <resultMap id="kingMap" type="king">
        <id column="kid" property="id" />
        <result column="kname" property="name" />
        
        <!--两种方式的比较-->
        <!-- 一对一映射关系 -->
        <!--<association property="queen" javaType="queen" resultMap="queenMap" columnPrefix="queen_"/>-->
        <!-- 一对多映射关系 -->
        <collection property="girls" ofType="girl" resultMap="girlMap" columnPrefix="girl_" />
        
    </resultMap>

    <resultMap id="queenMap" type="queen">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="king_id" property="kId" />
    </resultMap>
    
    <resultMap id="girlMap" type="girl">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="king_id" property="kId" />
    </resultMap>

    <!--sql查询语句根据实际情况书写-->
    <select id="findKingById" resultMap="kingMap">
        SELECT
            k.id kid,
            k.`name` kname,
            q.id queen_id,
            q.`name` queen_name,
            k.id queen_king_id,
            g.id girl_id,
            g.`name` girl_name,
            k.id girl_king_id
        FROM
            king k
        LEFT JOIN queen q ON k.id = q.k_id
        LEFT JOIN girl g ON g.k_id = k.id
        WHERE
            k.id = 27
    </select>

</mapper>
动态SQL
if
<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>
choose&when&otherwise

类似于java代码中的choose…case…default;

在标签内的内容,输入的条件符合哪个标签内的条件就执行哪一个标签内的内容,如果都不符合就执行标签内的内容

一旦有输入的条件有符合标签内的内容的,就执行这个标签内的内容,其他的和标签内的内容不再执行

  <select id="queryAllUserByCondition" resultType="user">
          SELECT * from `user`
            <choose>
             <when test="nickName != null">
                 nick_name like #{nickName}
             </when>
             <when test="status != null">
                 and `status` = #{status};
             </when>
             <otherwise>
                 and 1 = 1
             </otherwise>
           </choose>       
   </select>
forEach

允许指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量

允许指定开头与结尾的字符串以及在迭代结果之间放置分隔符

  <select id="selectPostIn" resultType="domain.blog.Post">
    SELECT *
    FROM POST P
    WHERE ID in
      <!--
		collection 当前不要遍历的对象 
		separator 遍历完一次后,在末尾添加的字符等。 
		open 遍历的sql以什么开头 
		close 遍历的sql以什么结尾
		-->
    <foreach item="item" index="index" collection="list"
        open="(" separator="," close=")">
          #{item}
    </foreach>
  </select> 
where

where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。

如果输出后语句的开头为“AND”或“OR”,where 元素也会将它们去除。

如下所示:

<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
        select * from t_blog 
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="content != null">
                and content = #{content}
            </if>
            <if test="owner != null">
                and owner = #{owner}
            </if>
        </where>
 </select>  
set

set 元素可以用于动态包含需要更新的列,而舍去其它的

<update id="updateAuthorIfNecessary">
  update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
  where id=#{id}
</update>

set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号 , 因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号

trim

trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefixsuffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverridessuffixOverrides

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  
</trim>
缓存
一级缓存(本地缓存)

Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中; 第二次以后是直接去缓存中取。 当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。

使用:

  1. 我们在一个 sqlSession 中,对 User 表根据id进行两次查询,查看他们发出sql语句的情况
@Test
public void testSelectOrderAndUserByOrderId(){
    //根据 sqlSessionFactory 产生 session
    SqlSession sqlSession = sessionFactory.openSession();
    String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //第一次查询,发出sql语句,并将查询的结果放入缓存中
    User u1 = userMapper.selectUserByUserId(1);
    System.out.println(u1);
     
    //第二次查询,由于是同一个sqlSession,会在缓存中查找查询结果
    //如果有,则直接从缓存中取出来,不和数据库进行交互
    User u2 = userMapper.selectUserByUserId(1);
    System.out.println(u2);
     
    sqlSession.close();
}
  1. 同样是对user表进行两次查询,只不过两次查询之间进行了一次update操作。
@Test
public void testSelectOrderAndUserByOrderId(){
    //根据 sqlSessionFactory 产生 session
    SqlSession sqlSession = sessionFactory.openSession();
    String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //第一次查询,发出sql语句,并将查询的结果放入缓存中
    User u1 = userMapper.selectUserByUserId(1);
    System.out.println(u1);
     
    //第二步进行了一次更新操作,sqlSession.commit()
    u1.setSex("女");
    userMapper.updateUserByUserId(u1);
    sqlSession.commit();
     
    //第二次查询,由于是同一个sqlSession.commit(),会清空缓存信息
    //则此次查询也会发出 sql 语句
    User u2 = userMapper.selectUserByUserId(1);
    System.out.println(u2);
     
    sqlSession.close();
}
二级缓存

Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。

使用:

1.在 SqlMapConfig.xml 文件开启二级缓存

<settings> 
    <!-- 开启二级缓存的支持 -->  
    <setting name="cacheEnabled" value="true"/> 
</settings> 

2.配置相关的 Mapper 映射文件

<?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="com.itheima.dao.IUserDao">  
    <!-- 开启二级缓存的支持 -->  
    <cache></cache> 
</mapper>

3.配置 statement 上面的 useCache 属性

<!-- 根据 id 查询 --> 
<select id="findById" resultType="user" parameterType="int" useCache="true">  
    select * from user where id = #{uid} 
</select> 

注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

基于注解的二级缓存
  1. 在 SqlMapConfig 中开启二级缓存支持
<!-- 配置二级缓存 --> 
<settings>  
    <!-- 开启二级缓存的支持 -->  
    <setting name="cacheEnabled" value="true"/> 
</settings>

2.在持久层接口中使用注解配置二级缓存

@CacheNamespace(blocking=true)
//mybatis 基于注解方式实现配置二级缓存 
public interface IUserDao { 
批量插入
实体类
@Getter
@Setter
@ToString
public class User {
    private Integer id;
    private String nickName;
    private Integer status;
    private Timestamp createtime;

    public User(Integer id, String nickName, Integer status, Timestamp createtime) {
        this.id = id;
        this.nickName = nickName;
        this.status = status;
        this.createtime = createtime;
    }
    public User() {
    }
}
接口
public interface UserMapper2 {
    List<User> queryAllUserByCondition(User condition);
    List<User> queryUserByIn(List<Integer> ids);
    int batchInsertByDynamicSql(List<User> userList);
    int insertUser(User user);
}
配置文件
 <!-- foreach的使用场合之 —— 批量插入 -->
    <insert id="batchInsertByDynamicSql">
        insert into user (nick_name, status, createtime)
        values
        <foreach collection="list" item="user" separator="," close=";">
            (#{user.nickName},#{user.status},#{user.createtime})
        </foreach>
    </insert>
    <insert id="insertUser">
        insert into user (nick_name, status, createtime)
        values
            (#{nickName},#{status},#{createtime})
    </insert>
foreach方法
private static void testBatchInsert(UserMapper2 mapper) {

        List<User> userList = new ArrayList<>();
        userList.add(new User(null, "中央", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "嬴政", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "昭君", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "媚娘", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "玉环", 1, new Timestamp(System.currentTimeMillis())));

        int rows = mapper.batchInsertByDynamicSql(userList);
        System.out.println("批量插入成功, rows: " + rows);
    }

就是通过foreach来拼接sql语句,但不能无限拼接

ExecutorType.BATCH方法
    private static void testBatchInsertByExecutorBatch(SqlSessionFactory sqlSessionFactory, UserMapper2 mapper) {

        // 获取一个自动提交事务、批量执行的sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, true);

        List<User> userList = new ArrayList<>();
        for(int i = 100; i < 200; i++) {
           userList.add(new User(null, "中央", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "嬴政", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "昭君", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "媚娘", 1, new Timestamp(System.currentTimeMillis())));
        userList.add(new User(null, "玉环", 1, new Timestamp(System.currentTimeMillis())));
        }
        //设置每次执行的sql语句数量
        int batchSize = 100;
        int count = 0;
        List<BatchResult> resultList = new ArrayList<>();
        for(User user : userList) {
            // ExecutorType.Batch方式这里返回的不是影响的条数,具体获取方法参见下面代码
            mapper.insertUser(user);
            count++;
            if(count % batchSize == 0) {
                //刷新
                resultList.addAll(sqlSession.flushStatements());
            }
        }
        if(count % batchSize != 0) {
            resultList.addAll(sqlSession.flushStatements());
        }
        int rows = 0;
        for(BatchResult batchResult : resultList) {
            int[] updateCounts = batchResult.getUpdateCounts();
            for(int updateCount : updateCounts) {
                rows += updateCount;
            }
        }
        System.out.println("批量插入成功,响应的行数:" + rows);

    }
Mybatis逆向工程
什么是Mybatis逆向工程?

​ 可以针对单表自动生成MyBatis执行所需要的代码,包括:Mapper.java,Mapper.xml,实体类。

Mybatis逆向工程有什么不足?

​ 逆向工程有它自身的局限性,逆向工程方法只能执行一次,如果再次执行就会重复生成对应的DAO接口,实体 类等资源。如果需要对表结构进行修改,那么就必须删除已经生成的所有资源,重新生成一次。

如何使用Mybatis逆向工程?

1.添加依赖jar包到pom.xml文件。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.southwind</groupId>
  <artifactId>MBGMaven</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>MBGMaven Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.25</version>
    </dependency>

    <dependency>  
      <groupId>org.mybatis.generator</groupId>  
      <artifactId>mybatis-generator-core</artifactId>  
      <version>1.3.2</version>  
    </dependency>

  </dependencies>
  <build>
    <finalName>MBGMaven</finalName>
  </build>
</project>

2.创建MBG配置文件generatorConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">

        <commentGenerator>
            <!-- 删除自动生成注释 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 配置数据库连接信息 -->
        <jdbcConnection 
            driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8" 
            userId="root"
            password="root">
        </jdbcConnection>

        <!-- 数据类型解析,false表示将DECIMAL和 NUMERIC类型解析为 Integer,true表示解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- 自动生成实体类存放的位置 -->
        <javaModelGenerator targetPackage="com.southwind.entity"
            targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- 自动生成Mapper.xml存放的位置 -->
        <sqlMapGenerator targetPackage="com.southwind.dao" 
            targetProject="./src/main/resources">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- 自动生成Mapper接口存放的位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="com.southwind.dao" 
            targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 指定数据库表 -->
        <table tableName="t_user" domainObjectName="User"></table>    

    </context>
</generatorConfiguration>

3.创建GeneratorMain类,执行自动生成资源的代码。

package com.southwind.main;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorMain {

    public static void main(String[] args) throws Exception {
        List<String> warnings = new ArrayList<String>();  
        boolean overwrite = true;  
        String genCfg = "/generatorConfig.xml";  
        File configFile = new File(GeneratorMain.class.getResource(genCfg).getFile());  
        ConfigurationParser cp = new ConfigurationParser(warnings);  
        Configuration config = null;  
        try {  
            config = cp.parseConfiguration(configFile);  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (XMLParserException e) {  
            e.printStackTrace();  
        }  
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);  
        MyBatisGenerator myBatisGenerator = null;  
        try {  
            myBatisGenerator = new MyBatisGenerator(config, callback, warnings);  
        } catch (InvalidConfigurationException e) {  
            e.printStackTrace();  
        }  
        try {  
            myBatisGenerator.generate(null);  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }      

    }
}

Spring与Mybatis整合

  1. 加入依赖

    <!-- mybatis-spring整合依赖,这个是最主要的一个依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.1</version>
    </dependency>
    
    <!-- Spring和数据源相关依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.20</version>
    </dependency>
    
  2. 在Spring bean配置文件中配置Mybatis、Spring整合bean SqlSessionFactoryBean

    <!-- 配置整合bean -->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源是必要参数 -->
        <property name="dataSource" ref="dataSource" />
        <!-- Mybatis核心配置文件其实大多数情况下都可以省略,通过指定属性可以间接设置核心配置文件中的参数 -->
        <!--<property name="configLocation" value="mybatis_conf.xml" />-->
    
        <!-- 省略mybatis核心配置文件后,可以通过类似下面这些特定属性,设置mybatis参数 -->
        <property name="typeAliasesPackage" value="com.lanou3g.mybatis.spring.bean" />
        <property name="mapperLocations" value="classpath:mapper/*.xml" />
    </bean>
    
  3. 在Spring bean配置文件中开启Mybatis Mapper扫描

    1. 需要使用mybatis schema

      配置方法,在bean配置文件的头部添加

      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
              http://mybatis.org/schema/mybatis-spring
              http://mybatis.org/schema/mybatis-spring.xsd">
      
    2. 开启Mybatis Mapper扫描

      开启Mybatis Mapper扫描的作用是:告诉Mybatis要创建哪个包下接口的实现类,并以bean的方式加入到SpringIOC容器中

      <!-- 开启Mapper扫描,Mybatis会创建将此包下的接口的实现类,并以bean的方式加入到SpringIOC容器中 -->
      <mybatis:scan base-package="com.lanou3g.mybatis.spring.mapper" />
      
  4. 创建实体类、mapper映射文件、Mapper接口(可以通过Mybatis逆向工程直接生成)

    Mapper接口

    @Repository	//此注解不是必须的,因为MessageMapper类的实现类是由Mybatis创建并放到ioc容器中的,不是由Spring来创建的。
    public interface MessageMapper {
        int insert(Message record);
        List<Message> selectAll();
    }
    

    实体类、映射文件 略

  5. 将Mapper接口用Spring自动注入的方式注入到需要的地方使用

    MessageService.java

    @Service
    public class MessageService {
        @Autowired
        MessageMapper messageMapper;
        public List<Message> queryAllMessage() {
            return messageMapper.selectAll();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值