MyBatis学习笔记

发布于:2022-11-11 ⋅ 阅读:(1352) ⋅ 点赞:(1)

目录

一 、MyBatis简单介绍

1、历史简介

2、特点

二、使用mybatis

1、导入依赖

2、编写核心配置文件 mybatis-config.xml

3、创建mapper接口 XXMapper

4、编写接口映射文件 XXMapper

5、编写测试类

6、配置log4j日日志功能(非必须)

三、 MyBatis获取参数值

1、获取单个参数值

2、获取多个参数值

四、MyBatis设置自定义结果集 resultMap

1、字段名和实体类中的属性名不一致

2、多对一映射处理

3、一对多映射处理

五、Mybatis的延迟加载

六、特殊sql语句的执行

1、模糊查询

2、批量删除

3、动态设置表名

4、在插入数据后获取自增的主键

七、动态sql

1、if

2、where

3、trim

4、choose、when、otherwise

5、foreach

八、MyBatis的缓存

 1、一级缓存

 2、二级缓存

九、MyBatis的逆向工程

十、Mybatis分页插件的使用


一 、MyBatis简单介绍

1、历史简介

MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。

2、特点

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的pojo映射成数据库中的记录
  • MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架
  • 简单易学,没有任何第三方依赖。
  • 灵活,MyBatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

二、使用mybatis

1、导入依赖

        <!-- Mybatis核心 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.11</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

2、编写核心配置文件 mybatis-config.xml

注:核心配置文件主要用于配置连接数据库的环境以及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"/>

    <!-- 设置别名 -->
    <typeAliases>
        <!-- 方法一 给单个类起别名 -->
        <!-- type:对应的类路径  alias:别名-->
        <typeAlias type="" alias=""/>

        <!-- 方法二 给某个包里面的所有类起别名,别名为类名 -->
        <!-- name:包路径-->
        <package name=""/>
    </typeAliases>

    <!--配置数据库信息-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="1010"/>
            </dataSource>
        </environment>
    </environments>


    <!-- 引入映射文件 -->
    <mappers>
        <!-- 引入单个映射文件 -->
        <mapper resource="com/mapper/XXMapper.xml"/>

        <!-- 引入某个包里的所有映射文件 -->
        <package name="com.mapper"/>
    </mappers>


</configuration>

3、创建mapper接口 XXMapper

public interface XXMapper {

    List<XX> select();

    int insert(XX xx);

    int update(XX xx);

    int delete(XX xx);

}

4、编写接口映射文件 XXMapper

<?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.mapper.XXMapper">

<!-- 注:id为对应方法名,参数类型可使用 @Param 指定 或 Map 类型传入-->

<!-- 查询 -->
<select id="" parameterType="" resultType="">
    <!--查询语句-->
</select>

<!-- 插入 -->
<insert id="" parameterType="">
    <!--插入语句-->
</insert>

<!-- 修改 -->
<update id="" parameterType="">
    <!--修改语句-->
</update>

<!-- 删除 -->
<delete id="" parameterType="">
    <!--删除语句-->
</delete>

</mapper>
    
<!-- 注:多个参数可使用 @Param 指定 或 Map 类型传入-->

5、编写测试类

public class MyTest {


    @Test
    public void test() throws IOException {
        
        //加载核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-conf.xml");
        //通过 SqlSessionFactoryBuilder 获取 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession
        SqlSession session = sqlSessionFactory.openSession();
        
        //获取Mapper接口对象
        XXMapper mapper = session.getMapper(XXMapper.class);
        
        //调用mapper接口中的方法执行操作


        //增删改方法执行后需要调用session.commit()方法提交事务
        session.close();

    }
}

6、配置log4j日日志功能(非必须)

a、导入依赖

<!-- log4j日志 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

b、添加配置文件 log4j.xml,存放在src/main/resources目录下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
        </layout>
    </appender>
<!-- (上面爆红的不管,不影响) -->

    <!-- level:设置日志级别 -->
    <!-- FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)-->
    <!-- 从左到右打印的内容越来越详细-->
    
    <logger name="java.sql">
        <level value="debug" />
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info" />
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>

三、 MyBatis获取参数值

1、获取单个参数值

直接通过 #{参数名} 获取即可,参数名可以任意

User selectUser(String username);
    <select id="selectUser" resultType="User">
        select * from user where username = #{username}
    </select>

2、获取多个参数值

当接口方法中有多个参数时,MyBatis会将多个参数保存在Map集合中,会以两种方式存储:

Map集合的键为arg0,arg1...后面的数字表示对应的参数位置(从0开始)

Map集合的键为param1,param2..后面的数字表示对应参数位置(从1开始)

两种方式是同时保存的,可用任意一种获取。

a、通过#{arg0}或#{param1}获取对应位置上的参数

    User login(String username, String password);
    <select id="login" resultType="User">
        select * from user where username = #{arg0} and password = #{arg1}
    </select>
    
<!--或者 select * from user where username = #{param1} and password = #{param2} -->
<!--也可以混合使用  select * from user where username = #{arg0} and password = #{param2}  -->

b、手动将参数保存在Map集合中,并传入Map集合作为参数,通过#{自定义键名}获取

和上面的一样,只不过Map是自定义的,并且只需要传入Map集合作为参数 

User login(Map<String,String>);

c、使用 注解@Param("")在接口方法中指定参数

该方式的原理和上两个一样,MyBatis会解析并将值保存在Map集合中,但是键是自定义的即@Param("")中的值

User login(@Param("username") String username,@Param("password") String password);

之后通过#{username},#{password}获取。

和第一种的区别就是,将MyBatis帮我们设置的键名arg0改成自定义username

除此之外,也可以继续通过#{param1}获取

d、传入实体类作为参数

该形式也是直接通过 #{属性名} 即可获得对应的值

User login(User user);

四、MyBatis设置自定义结果集 resultMap

1、字段名和实体类中的属性名不一致

a、可以通过为字段起别名的方式,保证和实体类中的属性名保持一致

b、字段名符合数据库规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)

在MyBatis的核心配置文件中设置全局配置信息mapUnderscoreToCamelCasetrue

之后在查询表中数据时,MyBatis会自动将_类型的字段名转换为驼峰

<setting name="mapUnderscoreToCamelCase"  value="true"/>

如 user_name ---->   userName

c、使用resultMap处理字段和属性的映射关系

<!--设置字段名和属性名之间的映射-->
<resultMap id="userMap" type="User">
    <id property="id" column="id"></id>
    <result property="userName" column="user_name"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
</resultMap>

<!--List<User> selectUser();-->
<select id="selectUser" resultMap="userMap">
    select * from t_user
</select>

2、多对一映射处理

以员工和部门为例,多个员工可以属于一个部门(即多对一)

a、使用级联方式处理映射关系

<resultMap id="empAndDept" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="did" property="dept.did"></result>
    <result column="dname" property="dept.dname"></result>
</resultMap>

b、使用association处理映射关系

<resultMap id="empAndDept" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>

<!-- 使用 association  关联部门信息 -->
    <association property="dept" javaType="Dept">
        <id column="did" property="did"></id>
        <result column="dname" property="dname"></result>
    </association>
</resultMap>

c、使用分布查询

<resultMap id="empAndDept" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>

<!--
    使用分布查询关联部门信息,select中的值代表部门映射文件中通过id查询部门的方法
    property:属性名
    select:对应分布查询的查询语句,输入值为包.方法名
    column:select查询方法中的查询条件
-->
    <association property="dept"
        select="com.mapper.DeptMapper.getDeptById" column="did">
    </association>
</resultMap>

对应的部门映射文件:

<!-- 
    对应Mapper接口中的方法:
    Dept getDeptById(@Param("did") int did); 
-->
<select id="getDeptById" resultType="Dept">
    select * from t_dept where did = #{did}
</select>

3、一对多映射处理

以部门和员工为例,一个部门可以有多个员工(即一对多)

a、使用 collection 进行映射


<resultMap id="deptAndEmp" type="Dept">
    <id property="did" column="did"></id>
    <result property="dname" column="dname"></result>
<!--
    ofType:对应集合中的对象类型
-->
    <collection property="emps" ofType="Emp">
        <id property="eid" column="eid"></id>
        <result property="ename" column="ename"></result>
    </collection>
</resultMap>

b、使用分布查询

<resultMap id="deptAndEmp" type="Dept">
    <id property="did" column="did"></id>
    <result property="dname" column="dname"></result>
    <collection property="emps"
        select="com.mapper.EmpMapper.getEmpListByDeptId" column="did">
    </collection>
</resultMap>

对应的员工映射文件:

<!--
    对应接口中的方法:
    List<Emp> getEmpListByDeptId(@Param("did") int did);
-->
<select id="getEmpListByDeptId" resultType="Emp">
    select * from t_emp where did = #{did}
</select>

五、Mybatis的延迟加载

延迟加载,顾名思义就是先不加载,等后面需要的时候再加载,大概意思就是你调用了相关的查询方法,但是你没有用到查询结果,那么该查询语句实际上是没有执行的。就是把要执行的语句等到你需要真正用到的时候再执行。

比如员工和部门表中,当你通过多对一中的分布查询来查员工信息时(此时查询员工和查询部门的方法是绑定在一起的),如果你在后面只是需要用到员工的id或名称那么mybatis只会帮我们查询员工信息表,不会查询部门表。如果你只是要获取部门信息,那就只执行查询部门的语句。

注:延迟加载在一对多和多对一的分布查询中使用

<!-- 在mybatis核心配置文件中开启全局延迟加载 -->
<setting name="mapUnderscoreToCamelCase"  value="true"/>

一旦开启,所有关联对象都会延迟加载。可通过在association 或 collection标签中的fetchType属性来设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"

六、特殊sql语句的执行

1、模糊查询

<!--List<User> selectByLike(@Param("value") String value);-->

<select id="selectByLike" resultType="User">

<!-- 方式一 -->
select * from t_user where username like '%${value}%'

<!-- 方式二 -->
select * from t_user where username like concat('%',#{value},'%')

<!-- 方式三 -->
select * from t_user where username like "%"#{value}"%"

</select>

2、批量删除

<!--int deleteMore(@Param("ids") String ids);-->
<delete id="deleteMore">
delete from t_user where id in (${ids})
</delete>

3、动态设置表名

<!--List<User> getAllUser(@Param("tableName") String tableName);-->
<select id="getAllUser" resultType="User">
select * from ${tableName}
</select>

4、在插入数据后获取自增的主键

<!-- useGeneratedKeys:设置开启自增    keyProperty:插入完成后返回的属性值  -->
<!--int insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user values(null,#{username},#{password},#{age},#{sex})
</insert>

上面插入代码执行后,会把自增的 id 值赋给之前 null 的 id ,之后直接获取当前id值就行了

七、动态sql

根据标签(如if、where、trim、choose、when、otherwise、foreach等)动态拼接sql语句

1、if

if 标签可通过对test属性的表达式进行判断,若表达式的结果为true,则执行标签中的内容,否则不执行。

<!-- 在test中输入要判断的表达式 -->
<if test="">
    <!-- 要拼接的sql语句 -->
</if>

 2、where

where 标签帮我们在语句中添加where关键字,一般和 if 标签 搭配使用:

如果 if 标签中的条件满足则拼接并可以帮我们去掉前面多余的and或or(无法去掉拼接语句后面的);

如果 where 标签里面的 if 标签都不满足条件,则不会添加where关键字;

<where>
    <if test="">
        <!-- 要拼接的sql语句 -->
    </if>
    <if test="">
         <!-- 要拼接的sql语句 -->
    </if>
</where>

3、trim

trim 标签可以动态的 去掉 添加 标签中的内容

trim 中的属性:

prefix:在trim标签中的内容的前面添加某些内容

prefixOverrides:在trim标签中的内容的前面去掉某些内容

suffix:在trim标签中的内容的后面添加某些内容

suffixOverrides:在trim标签中的内容的后面去掉某些内容

<trim prefix="XX" prefixOverrides="XX" suffix="XX" suffixOverrides="XX" >

</trim>

4、choose、when、otherwise

 这三个标签搭配使用可以实现if(){}else if(){}else的

<choose>
    <when test="">
         <!-- 要拼接的sql语句 -->
    </when>
    <when test="">
         <!-- 要拼接的sql语句 -->
    </when>
    <when test="">
         <!-- 要拼接的sql语句 -->
    </when>
    <otherwise>
         <!-- 要拼接的sql语句 -->
    </otherwise>
</choose>

5、foreach

foreach 标签中的属性:

 collection:要循环的数组或集合

item:集合或数组中的每一个数据

separator:每个循环体之间的分隔符

open:在foreach标签内容的开始处添加的内容

close:在foreach标签内容的结尾处添加的内容

例:根据id删除多条用户信息

<delete id="deleteBYIds">
    delete from user where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

八、MyBatis的缓存

MyBatis中的缓存有两个:一级缓存和二级缓存,默认为以及缓存。‘

缓存只有在查询时才存在(才有有意义),增删改没有缓存概念

 1、一级缓存

一级缓存是SqlSession级别的,即在同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。(即同一个查询语句只执行一次)。一级缓存默认是开启的,我们不需要配置任何东西。

注意,以下操作会清除一级缓存:

在两次查询期间执行了增删改操作;

提交或关闭SqlSession;

收到清除了缓存;

 2、二级缓存

二级缓存是SqlSessionFactory级别即在同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存。

二级缓存需要手动开启:

1、在核心配置文件中开启,这个看版本,有些版本默认开启,有些默认关闭。

<settings>
	<setting name = "cacheEnabled" value = "true" />
</settings>

2、在xxMapper.xml映射文件中使用 <cache /> 标签开启

<!--
cache中的属性:
    eviction:缓存回收策略
            LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。(默认)
            FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
            SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
            WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    flushInterval:设置刷新间隔,单位毫秒。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
    size:代表缓存最多可以存储多少个对象,正整数。
    readOnly:只读,true/false
            true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。,能会好一些。
            false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全(默认)。

-->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>

注意:二级缓存必须在SqlSession关闭或提交之后有效,并且对应的查询出来的实体类需要实现序列化。

缓存查询的顺序:二级 - -> 一级 - -> 数据库

先查询二级缓存是因为可能在其他 SqlSession 中查过有缓存记录了。

如果在二级和一级缓存中都没有则查询数据库。在数据库中查询的数据会先放在一级缓存中,当 SqlSession 关闭后,会把一级缓存会写入二级缓存。

九、MyBatis的逆向工程

在创建好数据库表,使用MyBatis的逆向工程负责根据数据库表,反向生成 Java实体类、 Mapper接口 和 Mapper映射文件。

 创建步骤/模板:

1、添加所需插件

<!-- 控制Maven在构建过程中相关配置 -->
<build>
    <!-- 构建过程中用到的插件 -->
    <plugins>
        <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>
            <!-- 插件的依赖 -->
            <dependencies>
                <!-- 逆向工程的核心依赖 -->
                <dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
                </dependency>

                <!-- 数据库连接池 -->
                <dependency>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                    <version>0.9.2</version>
                </dependency>

                <!-- MySQL驱动 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.8</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

2、创建逆向工程的配置文件: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>
    <!-- 上面爆红的可以不管,不影响-->
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    -->
    <context id="contextId" targetRuntime="MyBatis3">
        
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis"
                        userId="root"
                        password="root">
        </jdbcConnection>
        
        <!-- javaBean的生成策略
            targetPackage:生成的实体类所在的包
            targetProject:生成的实体类所在的位置(.表示工程路径)
        -->
        <javaModelGenerator targetPackage="com.bean"
                            targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.mapper" 
                                targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        
        <!-- 
            设置需要逆向生成的表,可以通过多个 table 标签设置多个表
            tableName:表名
            domainObjectName:实体类的类名
        -->
        <table tableName="t_user" domainObjectName="User"/>

    </context>
</generatorConfiguration>

3、在maven管理中双击执行generate

 此时会在相应目录生成相应文件,其中在XXExample类中提供了多种增删改查方法。

 

十、 Mybatis分页插件的使用

1、添加依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>

2、在核心配置文件中配置分页插件

<plugins>
    <!--设置分页插件-->
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

3、在查询功能前使用PageHelper.startPage((int pageNum, int pageSize)开启分页功能

其中,pageNum表示当前页的页码,pageSize表示每页显示的数量

4、查看分页信息

//list:分页之后的数据集合
PageInfo<T> pageInfo = new PageInfo<>(List<T> list)

 在上面代码中传入查询到的结果集合即可获取分页信息,包括:

pageNum:当前页的页码

pageSize:每页显示的条数

size:当前页显示的真实条数

total:总记录数

pages:总页数

prePage:上一页的页码

nextPage:下一页的页码

isFirstPage/isLastPage:是否为第一页/最后一页

hasPreviousPage/hasNextPage:是否存在上一页/下一页

更多内容可以查看 官网