实践MyBatis

MyBatisMyBatis Blog】,前身是iBatis,是一个ORM框架,半自动

mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!-- 别名 -->
    <typeAliases>
        <package name="wang.angi.sample.mybatis.spring.boot.starter.domain"/>
    </typeAliases>
   <environments default="development">
     <environment id="development">
       <transactionManager type="JDBC"/>
       <dataSource type="POOLED">
         <property name="driver" value="${driver}"/>
         <property name="url" value="${url}"/>
         <property name="username" value="${username}"/>
         <property name="password" value="${password}"/>
       </dataSource>
     </environment>
   </environments>
   <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

1
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>

properties

1
2
3
4
5
6
7
<properties>
	<!-- 子元素 -->
	<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
<!-- properties配置文件 -->
<properties resource="jdbc.properties"/>
<properties url="file:///properties/jdbc.properties"/>

settings

1
2
3
<settings>
	<setting name="cachedEnabled" value="true"/>
</settings>

typeAliases

MyBatis默认定义了一系列系统别名,也可以自定义别名,别名可以在MyBatis上下文中使用。不区分大小写。

1
2
3
4
5
6
7
8
9
10
11
12
<typeAliases>
	<!-- 精确定义 -->
	<typeAlias alias="role" type="wang.angi.sample.mybatis.dto.Role"/>
</typeAliases>

<typeAliases>
	<!-- 基于包扫描定义,递归当前包及子包,不支持Ant匹配 -->
    <!-- 如果使用了@Alias注解,则别名名称由注解定义-->
    <!-- 如果没有使用Alias注解,也会生成别名,只是别名的名字是类名首字母改为小写 -->
	<typeAlias package="wang.angi.sample.mybatis.dto"/>
	<typeAlias package="wang.angi"/>
</typeAliases>

typeHandlers

类型处理器,在设置参数或结果集映射时会进行类型转换,主要是Java类型和JDBC类型(org.apache.ibatis.type.JdbcType)的互相转换,MyBatis默认定义了一系列系统类型处理器,也可以自定义类型处理器。

自定义类型处理器需要实现接口:org.apache.ibatis.type.TypeHandler,MyBatis默认抽象实现:org.apache.ibatis.type.BaseTypeHandler

1
2
3
<typeHandlers>
  	<typeHandler jdbcType="VARCHAR" javaType="string" handler="wang.angi.sample.mybatis.typehandler.MyStringTypeHandler"/>
</typeHandlers>

枚举类型TypeHandler

EnumOrdinalTypeHandler:基于枚举下标传递参数

EnumTypeHandler:基于枚举名称传递参数

objectFactory

当将结果集映射到POJO时,会基于ObjectFactory去构建。一般而言MyBatis默认定义的ObjectFactory可以满足需求。

自定义则需要实现接口:ObjectFactory,MyBatis默认抽象实现:DefaultObjectFactory

1
2
<objectFactory type="wang.angi.sample.mybatis.objectfactory.CustomObjectFactory">
</objectFactory>

reflectorFactory

objectWrapperFactory

plugins

environments

数据库事务

数据源

databaseIdProvider

mappers

1
2
3
4
5
6
7
8
9
<mappers>
  <!-- classpath relative -->
  <mapper resource="wang/angi/sample/mybatis/mapper/roleMapper.xml"/>
  <mapper url="file:///mybatis/mapper/roleMapper.xml"/>
  <!-- 基于Mapper接口 -->
  <mapper name="wang.angi.sample.mybatis.mapper.roleMapper"/>
  <!-- 基于Mapper接口所在包 -->
  <package name="wang.angi.sample.mybatis.mapper"/>
</mappers>

SqlSessionFactoryBuilder

SqlSessionFactory

一般采用单例模式创建

SqlSession

类似JDBC中connection,非线程安全,随用随取,用完即毁。

1
2
3
4
5
6
7
8
9
// 直接通过SqlSession操作,不需要mapper接口,iBatis遗留方式,MyBatis不推荐使用,而是推荐使用Mapper
SqlSession session = sqlSessionFactory.openSession();
try {
  // [namespace.]<sqlId>
  Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
finally {
  session.close();
}

Mapper

非线程安全,从SQLSession获取,随用随取,用完即毁。

1
2
3
4
5
6
7
8
9
// 通过Mapper操作
SqlSession session = sqlSessionFactory.openSession();
try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}
finally {
  session.close();
}

基于反射生成Mapper实现

Mapper接口

1
2
3
public interface BlogMapper {
  Blog selectBlog(int id);
}

备注:如果直接使用SQLSession方式操作,可以不需要Mapper接口。

需要XML Mapper定义sql statement

XML Mapper

id与Mapper接口的方法名一致

BlogMapper.xml

1
2
3
4
5
6
1
2
3
4
5
6
<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
     select * from Blog where id = #{id}
  </select>
</mapper>

Annotation Mapper

直接在Mapper接口上定义sql statement,不需要XML Mapper

1
2
3
4
public interface CityMapper {
    @Select("SELECT * FROM CITY WHERE state = #{state}")
    City findByState(@Param("state") String state);
}

select

insert

update

delete

参数

1
#{id,javaType=int,jdbcType=NUMERIC,numericScale=2}
1
2
# 存在SQL注入的风险
ORDER BY ${columnName}

简单参数

1
2
3
4
5
6
1
2
3
4
5
6
<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
     select * from Blog where id = #{id}
  </select>
</mapper>

8种基本类型或包装类型的单个参数,可以不用指定parameterType

Map

多个有名参数

JavaBean

过多的有名参赛

@Param

少于6个参数有名参数

存储过程

mode=INT/OUT/INOUT

备注:parameterMap已经不推荐使用了

结果

resultType

resultMap

sql

核心功能

自动映射

autoMappingBehavior:自动映射行为,默认值:PARTIAL

NONE

PARTIAL

FULL

mapUnderscoreToCamelCase:是否开启数据库下划线到Java驼峰命名规则映射,默认值false。比如:created_by《-》createdBy

级联

lazyLoadingEnabled:是否开启延时加载,全局,默认值:false

aggressiveLazyLoading:是否层级延时加载,全局,默认值:true

fetchType:级联获取模式,可取值:eager和lazy,用于<association/><collection/>,默认值由aggressiveLazyLoading决定

缓存

分页

RowBounds

MyBatis自带,内存分页

1
2
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10));
roleMapper.findRolesByName("role", new RowBounds(0,5));

动态SQL

Criterion:一个筛选条件,比如>、<、=、between、in等

Criteria:一组筛选条件,之间and关系

List<Criteria> oredCriteria:一组Criteria,之间or关系