Mybatis学习笔记
简介
(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 configurationPUBLIC "-//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 mapperPUBLIC "-//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 order:before (先执行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 generatorConfigurationPUBLIC "-//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可获取,总页数,总件数,单页数据数,等待。