Mybatis学习笔记

时间:2024-02-16 15:24:07

简介

(1) 持久层框架比较

hibernate:全表映射,效率高,多表联合查询支持差。不支持存储过程,不能优化SQL。

mybatis:半自动映射,手动匹配映射关系,手动编写SQL,工作量大。可动态SQL,优化SQL。

(2) 下载jar包方式

官网:https://github.com/mybatis

解压 jar  将 mybatis.jar加入项目lib中

 (3) maven依赖方式

查询网址:https://mvnrepository.com

1. 核心配置

根标签:<configuration>  

Spring整合项目不需要配置Mybatis核心配置

属性按属性配置:properties>settings>typeAliases>typeHandlers>objectFactory>objectWrapperFactory>reflectFactory>plugins>environments>databaseIdProvider>mappers

文件夹【src】或【java/main/resources】下新建mybatis-config.xml(内容可从官方API复制)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

1.1 <properties> 属性

1.1.1 外部引用

文件夹【src】或【java/main/resources】下新建【db.properties】或【jdbc.properties】文件

1.1.2 内部属性

1.1.3 内外属性共用 

    <!-- 属性 -->
    <properties resource="org/mybatis/mybatis-config.properties" >
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

1.2 <settings> 设置

用来改变Mybatis运行行为,开启二级缓存,开启延时加载等。

(1) 二级缓存:<setting name="cacheEnabled" value="false" />// true(开启), false(默认关闭)

(2) 延时加载:<setting name="lazyLoadingEnabled" value="false" /> // true(开启), false(默认关闭)

<!-- 设置 -->
    <settings>
        <!-- 二级缓存 true:开启,false(default):关闭-->
        <setting name="cacheEnabled" value="false" />
        <!-- 延迟加载 true:开启,false(default):关闭(立即加载)-->
        <setting name="lazyLoadingEnabled" value="false" />
        <!-- 只有lazyLoadingEnabled为true才生效-->
        <!-- 按需加载 true:开启(默认,任意访问加载),false:关闭(深度延迟)-->
        <setting name="aggressiveLazyLoading" value="true" />
        <!-- 是否允许单一语句返回多结果集 true(default):允许,false:不允许-->
        <setting name="multipleResultSetsEnabled" value="true" />
        <!-- 使用列标签代替列名 true(default):允许,false:不允许-->
        <setting name="useColumnLabel" value="true"/>
        <!-- JDBC自动生成主键 true:允许,false(default):不允许-->
        <setting name="useGeneratedKeys" value="false"/>
        <!-- 自动映射列名属性 NONE:取消自动,PARTIAL(default):只映射没有嵌套结果集的映射,FULL:自动映射任意结果集-->
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
        <!-- 默认执行器 SIMPLE(default):普通,REUSE:预处理,BATCH:批处理-->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!-- 超时时间(等待数据库响应秒数,随驱动默认)-->
        <setting name="defaultStatementTimeout" value="25"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="safeRowBoundsEnabled" value="false"/>
        <setting name="safeResultHandlerEnabled" value="true"/>
        <!-- 自动驼峰命名规则 true:允许,false(default):不允许-->
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <setting name="localCacheScope" value="SESSION"/>
        <!-- 为null指定JDBC类型 NULL,VARCHAR,OTHER(default)-->
        <setting name="jdbcTypeForNull" value="OTHER"/>
        <setting name="lazyLoadTriggerMethods" value=""/>
        <setting name="defaultScriptingLanguage" value=""/>
        <setting name="returnInstanceForEmptyRow" value=""/>
        <setting name="logPrefix" value=""/>
        <setting name="logImpl" value=""/>
        <setting name="vfsImpl" value=""/>
        <setting name="useActualParamName" value=""/>
        <setting name="configurationFactory" value=""/>
    </settings>

1.3 <typeAliases> 类型命名

映射文件查询的返回值匹配的类型别名

1.3.1 自定义别名 

(1) 默认配置:

核心配置:无

映射配置:<select id="xx" resultType="包名.类名"/> 

(2) 指定别名:

核心配置:<typeAlias alias="别名" type="包名.类名" />

映射配置:<select id="xx" resultType="别名"/> 

(3) 类名别名:

核心配置:<typeAlias type="包名.类名" />

映射配置:<select id="xx" resultType="不区分大小写类名"/> 

(4) 全包命名:

核心配置:<package name="包名.包名" /> 

映射配置:<select id="xx" resultType="不区分大小写类名"/> 

注释:(3)(4)更改别名,实体类类注解@Alias(value="别名") // @alias("别名")

    <!-- 类型别名 -->
    <typeAliases>
        <!-- 方式1:单个类别名指定-->
        <typeAlias alias="user" type="com.entity.User"/>
        <!-- 方式2:省略alias,默认类名,Bean加@Alias(value="user")注解 改别名 -->
        <typeAlias type="com.entity.User"/>
        <!-- 方式3:自动扫描包,默认类名,Bean加@Alias(value="user")注解 改别名 -->
        <package name="com.entity"/>
    </typeAliases>

1.3.2 内置别名

注释:alias属性映射文件中使用时不区分大小写(type为对应接口函数的返回值类型)

    <typeAliases>
        <!-- 基本类型,别名前加_, alias为别名, type为java类型-->
        <typeAlias alias="_byte" type="byte"/>
        <typeAlias alias="_short" type="short"/>
        <typeAlias alias="_int" type="int"/>
        <typeAlias alias="_integer" type="int"/>
        <typeAlias alias="_long" type="long"/>
        <typeAlias alias="_float" type="float"/>
        <typeAlias alias="_double" type="double"/>
        <typeAlias alias="_boolean" type="boolean"/>
        <typeAlias alias="_char" type="char"/><!-- 3.5.10-->
        <typeAlias alias="_character" type="char"/><!-- 3.5.10-->

        <!-- 引用类型-->
        <typeAlias alias="byte" type="Byte"/>
        <typeAlias alias="short" type="Short"/>
        <typeAlias alias="int" type="Integer"/>
        <typeAlias alias="integer" type="Integer"/>
        <typeAlias alias="long" type="Long"/>
        <typeAlias alias="float" type="Float"/>
        <typeAlias alias="double" type="Double"/>
        <typeAlias alias="boolean" type="Boolean"/>
        <typeAlias alias="char" type="Char"/><!-- 3.5.10-->
        <typeAlias alias="character" type="Char"/><!-- 3.5.10-->
        <typeAlias alias="string" type="String"/>

        <typeAlias alias="date" type="Date"/>
        <typeAlias alias="decimal" type="BigDecimal"/>
        <typeAlias alias="bigDecimal" type="BigDecimal"/>
        <typeAlias alias="bigInteger" type="BigInteger"/>
        <typeAlias alias="object" type="Object"/>
        
        <typeAlias alias="date[]" type="Date[]"/>
        <typeAlias alias="decimal[]" type="BigDecimal[]"/>
        <typeAlias alias="bigDecimal[]" type="BigDecimal[]"/>
        <typeAlias alias="bigInteger[]" type="BigInteger[]"/>
        <typeAlias alias="object[]" type="Object[]"/>

        <typeAlias alias="map" type="Map"/>
        <typeAlias alias="hashMap" type="HashMap"/>
        <typeAlias alias="list" type="List"/>
        <typeAlias alias="arrayList" type="ArrayList"/>
        <typeAlias alias="collection" type="Collection"/>
        <typeAlias alias="iterator" type="Iterator"/>
    </typeAliases>

1.4 <typeHandlers> 类型处理器

java类型与jdbc类型转换,映射文件不用指定参数类型,默认自动映射。

1.5 <objectFactory> 对象工厂

1.6 <plugins> 插件

1.7 <environments> 数据库连接环境

(1) 数据库连接环境配置:<environments default="默认id">

(2) 数据库连接环境:<environment id="xx">

(3) 事务管理器:<transactionManager type="JDBC"/> //JDBC手动提交事务,MANAGED被管理

(4) 数据源:<dataSource type="POOLED"> //POOLED连接池,UNPOOLED每次打开关闭,JNDI其它。

(5) 参数:<property name="driver|url|username|password" value="${xx}" /> 

    <!--配置多个连接数据库的环境-->
    <environments default="development"><!-- default:默认连接环境-->
        <!-- 单个数据库连接环境 -->
        <environment id="development"><!-- id:唯一标识 -->
            <!-- 事务管理器 -->
            <!-- type: JDBC 执行SQL 使用JDBC原生事务管理,手动提交回滚 -->
            <!-- type: MANAGED 被管理 -->
            <transactionManager type="JDBC"/>
            
            <!-- 配置数据库信息 -->
            <!-- type: POOLED 使用数据库连接池,缓存数据连接 -->
            <!-- type: UNPOOLED 每次请求打开关闭连接 -->
            <!-- type: JNDI 使用其他管理的数据源 -->
            <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>

1.8 <databaseIdProvider> 数据库厂商表示

1.9 <mappers> 映射器

1.9.1 核心配置映射器 

    <!--引入映射文件-->
    <mappers>
        <!-- 方式1: 类路径-->
        <mapper resource="com/mappers/UserMapper.xml"/>
        <!-- 方式2: 本地文件路径, 盘符后正反斜线效果相同-->
        <mapper url="file:///D:\com\mappers\UserMapper.xml"/>
        <!-- 方式3: 接口类(注解方式)-->
        <mapper class="com.mappers.UserMapper"/>
        <!-- 方式4: 全包扫描-->
        <package name="com.mappers"/>
    </mappers>

1.9.2 映射文件

(1) 命名空间:<mapper namespace="包.类">...</mapper>

注释:特殊符号用<![CDATA[ > ]]> 包裹,也可写文本  <![CDATA[ where a > 1 and ... ]]>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mappers.UserMapper">
    <select id="selectUser" resultType="user">
        select * from user
    </select>
</mapper>

2. 工厂类

2.1 配置文件 

加载: InputStream in = Resource.getResourceAsStream("mybatis-config.xml");

2.2 工厂类

获取:SqlSessionFactory ssf = new SqlSessionFactoryBuiler().build(in);

注释:sqlsessionFactory线程安全整个应用执行期间都存在创建多个会使得数据库资源耗尽。 

2.3 会话 

2.3.1 手动提交

(1) 获取会话:SqlSession ss = ssf.openSession(); 

(2) 手动提交: ss.commit();

2.3.2 自动提交

(1) 获取会话:SqlSession ss = ssf.openSession(true);

注释:SQL执行后自动提交

2.3.3 关闭会话

(1) 关闭会话:ss.close();

2.4 接口

(1) 获取接口对象:XxMapper mapper = ss.getMapper(XxMapper.class);

(2) 指定映射文件:int result = ss.insert | selectList("con.xx.UserMapper.adduser", User);

2.5 缓存

2.5.1 一级缓存

1级缓存是SqlSession 会话级别,默认开启,不同sqlSession的一级缓存不共享。

(1) 一级缓存失效:1.sqlSession不同,2.查询条件不同,3.执行了增删改SQL,4.手动清空(sqlSession.clearCache()) 

2.5.2 二级缓存

2级缓存时SqlSessionFactory级别,默认关闭,缓存数据在sqlSession关闭后后生效。

(1) 开启2级缓存:核心配置settings <setting name="cacheEnabled" value="true" />

(2) 映射文件配置:添加 <cache eviction="LRU" flushInterval="30000" size ="512" readOnly="true" />

注释:eviction(缓存回收策略):LRU(最长时间不使用),FIFL(先进先出) 

注释:flushinterval 刷新间隔毫秒,默认无间隔

注释:size 缓存对象个数(正整数)

注释:readonly : true(只读缓存,未调用者返回相同实例,不能修改) false(读写缓存,默认)

(3) 实体类:实现序列号接口(implements Serializable

注释:优先查2级缓存

3. 参数

3.1 获取参数方式

(1) ${参数}  //相当于字符串拼接,有SQL注入问题,转换后值没有引号。

必须使用场景: 1批量删除(传"1,2,3",接 in(${参数}=1,2,3)), 2 动态表名( select * from ${参数})

(2) #{参数}  // 相当于jdbc的预编译,可防止SQL注入问,转换后的值有引号。

必须使用场景:模糊查询( like '%${参}%')不安全,替代方式1( like concat('%', #{xx}, '%')), 替代方式2( like "%"#{xx}"%")

3.2 传参与接参

3.2.1 单字面量

可指定任意名称获取参数值。

3.2.2 多字面量

方式1:#{arg0}, #{arg1},...

方式2:#{param1}, #{param2},...

3.2.3 map

通过map的key获取参数

3.2.4 实体类

通过实体类的属性获取

3.2.5 注解

注解指定别名 

3.3 参数类型 parameterType(增删改查通用)

注释:可选属性 mybatis通过Typehandler推断 可自动设置

3.4 参数映射 parameterMap(查询专有)

注释:不推荐使用的,旧的参数映射方式

4. 结果集

4.1 字面量结果

注释:取得多条结果用List<String>接收返回值

4.2 map结果

* 需要保存DB字段类型自动转换后一致,否则强转会失败。

(1) 单条数据map 

(2) 多条数据 List<map>

 (3) 多条数据 Map<map>

注释:添加接口函数的注解(表主键)

4.3 结果类型(resultType)

(1) 字段名相同,自动映射。 

注释:不一致也可以通过查询字段别名的方式保持一致

(2) 设置自动驼峰转换。

4.4 结果映射(resultMap)

resultMap主要用来处理 表字段和java属性名不一致的情况。 

id:唯一标识

type:指定映射的实体类

4.4.1 普通结果集(result)

column:指定查询出的数据库字段名

property:指定实体类属性名

javaType:可省略

注释:有驼峰转换时,property指定下滑字段,column指定驼峰,也可以正常获取数据,但是必须转换后是相同字段名(user_id与userId可以,user_id与id不可以)

4.4.2 构造器结果集(constructor)

4.4.3 主键结果集(id)

4.4.4 一对一结果映射(association)

(1) 文件内部一对一

(2) 分步查询:文件外部子查询

association的column:主查询字段(用来做子查询条件)

(3) 延迟加载:

默认为关闭状态(立即加载),开启需设置全局setting.lazyLoadingEnabled

根据【aggressiveLazyLoading】的值做处理,true:访问任意属性加载,false访问对应的属性才加载(执行sql)。 

 个别SQL不开启延迟加载的设定:<association fetchType="lazy(延迟加载) | eager(立即加载) "

4.4.5 一对多结果映射(collection)

(1) 文件内部一对多

(2) 分步查询:文件外部一对多

(3) 延迟加载

参照association 

4.4.6 discriminator

5. 增删改查

5.1 查询

(1) id:唯一标识

(2) resultType:返回值类型

(3) resultMap:返回值映射

(4) flushCache:执行SQL后清除缓存,默认false

(5) useCache:开启二级缓存,默认true

(6) timeout:超时时间,单位秒,超时抛异常

(7) fetchSize:记录总条数

(8) statementType:JDBC工作模式(STATEMENT, PREPARED默认, CALLABLE)

(9) resultSetType:结果集类型(Forward_only, Scroll_Sensitive, Scroll_insensitive)

5.2 插入

(1) id:唯一标识

(2) flushCache:执行SQL后清除缓存,默认false

(3) timeout:超时时间,单位秒,超时抛异常

(4) statementType:JDBC工作模式(STATEMENT, PREPARED默认, CALLABLE)

(5) keyProperty:插入的返回值赋给(参数)实体类的某个属性(一般是主键),多个属性逗号分割。

(6) keyColumn:设置位置列名指定返回字段(主键不是第一列时设置)多个主键逗号分割。

(7) useGeneratedKeys:使用jdbc的getGeneratedKyes方法取数据库内部主键,默认false

(8) 获取自增主键(mysql, sqlserver)

(9) 获取自增主键(oracle)

注释:oracle不支持上记(keyProperty, keyColumn, useGeneratedKeys)主键自增

selectKey orderbefore (先执行selectKey 再执行insert) after (先执行Insert 再执行 selectKey)

    <insert id="addUser"
            parameterType="entity.User"
            keyProperty="id,userName"
            keyColumn="2,3"
    >
        <selectKey keyProperty="id"
                   resultType="Integer"
                   order="BEFORE"
                   statementType="PREPARED"
        >
            select if(max(id) is null, 1, max(id)) as newId from user
        </selectKey>
        insert into user(id, username, name)
        values (#{id}, #{username}, #{name})
    </insert>

5.3 更新

注释:同插入一样

(1) id:唯一标识

(2) flushCache:执行SQL后清除缓存,默认false

(3) timeout:超时时间,单位秒,超时抛异常

(4) statementType:JDBC工作模式(STATEMENT, PREPARED默认, CALLABLE)

(5) keyProperty:插入的返回值赋给(参数)实体类的某个属性(一般是主键),多个属性逗号分割。

(6) keyColumn:设置位置列名指定返回字段(主键不是第一列时设置)多个主键逗号分割。

(7) useGeneratedKeys:使用jdbc的getGeneratedKyes方法取数据库内部主键,默认false

5.4 删除

(1) id:唯一标识

(2) flushCache:执行SQL后清除缓存,默认false

(3) timeout:超时时间,单位秒,超时抛异常

(4) statementType:JDBC工作模式(STATEMENT, PREPARED默认, CALLABLE)

6. SQL元素

(1) 内部无参SQL

(2) 内部有参SQL

(3) 外部SQL

7. 动态SQL

7.1. if 单条件判断

注释:<if test=" xx == 1"> <if test=" xx == '2' ">  不能同时使用,有类型问题

(1) 条件语法:<if test="表达式"> sql内容 </if>

(2) 判空与非空:参数==null, 参数!=null, 参数=='', 参数 != '' // 单双引号可互换

(3) 逻辑控制:!,  and,  or

7.2. choose 多条件判断

(1) choose:没有属性

(2) when: test="表达式" // 多个when条件,只处理其中一个

(3) otherwise:没有属性 用于默认情况

7.3. where

注释:自动拼接where  并将第一个条件中and或or去掉,解决where 1=1 后的条件拼and的问题。if条件都不满足则没有where关键字 ,不能去除sql末尾关键字。

7.4. trim

(1) prefix添加前缀,没有满足条件的if则不添加内容

(2) prefixOverrides去除首个if条件开头的指定字符,多个字符用|分割

(3) suffix添加整个语句后缀,没有满足条件的if则不添加内容

(4) suffixOverides去掉最后一个if条件结尾的指定字符,多个字符用|分割

7.5. set

注释:主要用于更新,拼接set语句,去掉最后的,分割

7.6. foreach

(1) item每次循环的元素,map的值

(2) index当前元素(数组,list)的下标, map的键

(3) collection:接口参数名(类型可为Array, List, Map)

(4) open语句前添加的符号

(5) close语句后添加的符号

(6) separator每个元素的间隔符号

list

map

7.7. bind

注释:主要用于模糊查询,${...} 无法防止sql注入。concat只适用于mysql, oracle用|| ,不利于项目移植。

相当于将参数与%重新拼接成新的参数 

8. 注解SQL

注释:注解SQL无需配置映射xml,需要改 mybatis-config.xml配置,<mapper class="com.mybatis.xxMapper" /> 或全局配置<package name="com.mappers"/> 注解mapper接口与映射文件mapper接口可以放在同一个包下。

8.1 @Select:

8.2 @Insert: 

8.3 @Update:

8.4 @Delete:

8.5 一对一注解查询

映射集合:@Results

映射属性:@Result (column 字段|子查询条件,property 实体类属性)

一对一映射:one=@One(select="包.mapper.方法")

8.6 一对多注解查询

9 其它

9.1 逆向工程 

根据数据库生成,实体类,接口,映射文件。

(1) 创建maven项目,

(2) 引入插件

<plugins>
  <plugin>
    <groupid>org.mybatis.generator</groupid>
    <artifactid>mybatis-generator-maven-plugin</artifactid>
    <version>1.3.0</version>
    <depentencies>
      <dependency>
        <!-- 核心包 -->
        <groupid>org.mybatis.generator</groupid>
        <artifactid>mybatis-generator-core</artifactid>
        <version>1.3.2</version>
      </denpendency>
      <dependency>
        <!-- 数据库连接池 -->
        <groupid>com.mchange</groupid>
        <artifactid>c3p0</artifactid>
        <version>0.9.2</version>
      </denpendency>
      <dependency>
        <!-- 数据库驱动 -->
        ...
      </denpendency>
  </plugin>
</plugins>

(3) 创建逆向工程配置文件(generatorConfig.xml 文件名固定)

注释:enableSubPackages是否根据.生成子包,trimStrings是否自动去空格

<?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>
  <!-- MyBatis3Simple:基本crud,MyBatis3:基本crud及条件更新-->
  <context id="DB2Tables" targetRuntime="MyBatis3Simple">
    <!-- 数据库连接信息 -->
    <jdbcConnection 
      driverClass="com.mysql.jdbc.Driver"
      connectionURL="jdbc:mysql://localhost:3306/mybatis"
      userId="root"
      password="root">
    </jdbcConnection>
    <!-- javaBean生成策略 -->
    <javaModelGenerator targetPackage="com.test.mybatis.bean" 
      targetProject=".\src\main\java">
      <property name="enableSubPackages" value="true"/>
      <property name="trimStrings" value="true" />
    </javaModelGenerator>
    <!-- 映射文件生成策略 -->
    <sqlMapGenerator targetPackage="com.test.mybatis.mapper" 
      targetProject=".\src\main\resources">
      <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>
    <!-- 接口生成策略 -->
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.test.mybatis.mapper"
      targetProject=".\src\main\java\mapper">
      <property name="enableSubPackages" value="true" />
    </javaClientGenerator>
    <!-- 表配置(tableName *代表所有表)-->
    <table tableName="t_user" domainObjectName="User" />
  </context>
</generatorConfiguration>

(4) 双击执行插件(重新生成需要先删除旧文件) 

(5) 更新条件(Mybatis3)

mapper.selectByExample(null)// 查询所有数据

Example e = new Example(); 

e.createCriteria()//创建一个条件

  .and字段名xx() // and连接条件

  .or() //or连接后面条件

  .and...

mapper.updateByPrimaryKey(实体类) // null字段正常更新

mapper.updateByPrimaryKeySelective(实体类) //不更新值为null的属性。

9.2 分页插件

(1) 导入依赖(pom.xml)

<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(第几页, 一页件数);

mapper.select... //可获取到对应的件数数据

(4) 获取全部数据后分页

PageInfo<实体类> page= new PageInfo(list, 总页数);

// page可获取,总页数,总件数,单页数据数,等待。