mybatis 快速入门及配置文件详解
1、mybatis
前身iBatis,优秀的持久层框架,支持定制化SQL、存储过程以及高级映射。本质是半自动的ORM框架,除和POJO的映射外,还需要自己编写sql。
2、ORM
对象关系映射Object Relational Mapping,ORM模型就是数据库的表和简单的Java对象(POJO)的映射模型。
3、快速入门(maven 工程)
一、pom.xml 中加入mybatis依赖
二、新建mybatis 核心配置文件:mybatis-config.xml
三、新建mapper 接口和映射mapper.xml 文件。
3.1 代码
包结构
3.1.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mybatis-first</groupId>
<artifactId>com.aeolusway.mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.1.2 核心配置文件mybatis-config.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="db.properties"></properties>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="jdbc"></transactionManager>
<dataSource type="UNPOOLED">
<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="sqlmapper/UserMapper.xml" />
</mappers>
</configuration>
3.1.3 mapper 接口:UserMapper
package com.aeolusway.mapper;
import com.aeolusway.entity.User;
public interface UserMapper {
User selectByPrimaryKey(Integer id);
}
映射xml文件:UserMapper.xml
<?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.aeolusway.mapper.UserMapper">
<select id="selectByPrimaryKey" resultType="com.aeolusway.entity.User" parameterType="java.lang.Integer">
select
id,
user_name ,
real_name ,
sex,
mobile,
email,
note,
position_id positionId
from user
where id = #{id,jdbcType=INTEGER}
</select>
</mapper>
3.1.4 其他文件
db.properties:数据库连接信息,也可以配置在mybatis-config.xml 文件中
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
jdbc_username=root
jdbc_password=root
对象实体:User
package com.aeolusway.entity;
public class User {
private Integer id;
private String userName;
private String realName;
private Byte sex;
private String mobile;
private String email;
private String note;
private Integer positionId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public Byte getSex() {
return sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Integer getPositionId() {
return positionId;
}
public void setPositionId(Integer positionId) {
this.positionId = positionId;
}
@Override
public String toString() {
return "User{" + "id=" + id + ", userName='" + userName + '\'' + ", realName='" + realName + '\'' + ", sex=" + sex + ", mobile='" + mobile + '\'' + ", email='" + email + '\'' + ", note='" + note + '\'' + ", positionId=" + positionId + '}';
}
}
测试类 MybatisFirst
package com.aeolusway.test;
import com.aeolusway.entity.User;
import com.aeolusway.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MybatisFirst {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void quickStart(){
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行查询语句并返回结果
User user = mapper.selectByPrimaryKey(1);
System.out.println(user.toString());
}
}
4、入门核心类
mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/configuration.html
mybatis的应用都是基于一个SqlSessionFactory 实例为核心的。
4.1 SqlSessionFactoryBuilder
读取xml 配置文件(或预先定制的configuration 实例),使用建造则模式构建出SqlSessionFactory实例,创建SqlSessionFactory实例后,就不需要这个类了,所以最佳作用域:方法级别。
4.2 SqlSessionFactory
用于创建SqlSession,而SqlSession代表的是一次数据库链接,所以SqlSessionFactory 需要在运行期间一直存在,不应重复多次创建(使用单例模式或者静态单例模式保证这一点),最佳作用域:程序整个生命周期。
4.3 SqlSession
代表一次数据库连接,SqlSession 包含了SQL所需要的所有方法,(我们通过mapper接口操作数据库,实际上使用的是sqlSession的方法,其实iBatis就是这样做的。后面分析源码会具体讨论)。SqlSession 不是线程安全的,所以为了保证线程安全,每个线程都应该拥有自己的SqlSsession 实例,不能被共享,所以最佳作用域:方法级别。
4.4 SQL Mapping
由一个mapper 接口和映射文件xml组成,包含了要执行的sql语句和结果集映射规则,映射器接口的实例是从SqlSession 中获取的,所以最佳作用域:方法级别。
5、配置文件详解
5.1 核心配置文件mybatis-config.xml
mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/configuration.html
5.1.1 properties
属性配置,可引入外部属性配置文件,也可通过properties的子元素property配置。
<properties resource="db.properties"></properties>
//引入的就是外部属性文件:db.properties,
// 然后通过${***} 获取属性
5.1.2 settings
配置mybatis的一些全局属性,改变mybatis的运行时行为。
<settings>
<!-- 在自动隐射时,数据库表字段的命名规则(“——”分隔)改为驼峰命名规则) -->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!-- 取消所有的按需加载,一次性把数据全部加载出来 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
其他属性(部分常用属性)如下:(还有很多,可以去官网查看:http://www.mybatis.org/mybatis-3/zh/configuration.html)
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。 | true | false | false (在 3.4.1 及之前的版本默认值为 true) |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 |
5.1.3 typeAliases
设置别名,方便映射时使用,除开系统定义的别名外,自己也可以定义别名
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
</typeAliases>
// 当这样配置时,Author可以用在任何使用 domain.blog.Author的地方。
5.1.4 typeHandlers
类型处理器,用于jdbcType 和javaType之间的转换,mybatis定义了很多类型处理器。也可以自定义类型处理器来处理mybatis 不支持或非标准的类型转换,具体做法是,实现org.apache.ibatis.type.TypeHandler 接口或者继承org.apache.ibatis.type.BaseTypeHandler类,然后可以选择性的将其映射到一个jdbc类型,然后在核心配置文件中引入自定的类型处理器。
<typeHandlers>
<!-- 引入自定义的ExampleTypeHandler 类型处理器 -->
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
5.1.5 ObjectFactory
对象工厂,mybatis 每次创建结果对象的新实例时,都会通过一个对象工厂的实例来完成。mybatis 默认使用DefaultObjectFactory ,DefaultObjectFactory做的仅仅是实例化目标类,如果想要覆盖工厂的默认行为,可以创建自己的对象工厂来实现,绝大部分情况下我们是不需要这样做的。
5.1.6 plugins
引入插件,mybatis允许在语句(已映射的)执行过程中的某一点进行拦截调用。插件开发后面章节会讲到。
5.1.7 environments
配置数据源,每个数据源的配置分为数据库源和事务管理器的配置,可以配置多个数据源,但每个 SqlSessionFactory 实例只能选择一种环境。
<environments default="development">
<environment id="development">
<transactionManager type="jdbc"></transactionManager>
<dataSource type="UNPOOLED">
<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>
environment 元素是配置一个数据源的开始,属性id是它的唯一标识
transactionManager:元素配置数据库事务,其中type属性有三种配置方式
jdbc,采用jdbc的方式管理事务;
managed,采用容器的方式管理事务,在JNDI数据源中使用;
自定义,自定义数据库事务管理办法;
dataSource:元素配置数据源连接信息,type属性是连接数据库的方式配置,有四种配置方式
UNPOOLED 非连接池方式连接
POOLED 使用连接池连接
JNDI 使用JNDI数据源
自定义数据源
5.1.8 databaseIdProvider
数据库厂商id 配置,MyBatis根据不同的数据库厂商执行不同的语句,用于一个系统内多厂商数据源支持。
5.1.9 mapper
引入映射器,三种当时配置
<mappers>
<!--
1、classPath下资源引用:
直接映射到相应的mapper文件 -->
<mapper resource="sqlmapper/UserMapper.xml" />
<!—-
2、类注册方式引用:
通过类扫描mapper文件 -->
<mapper class="com.aeolusway.mapper.UserMapper" />
<!—
3、包名引入引射器名:
扫描包下所有的mapper文件,
这种映射mapper.xml 和mapper 接口名称要相同 -->
<package name="com.aeolusway.mapper"/>
</mappers>
5.2 mapper.xml映射文件
- cache:配置二级缓存
- cache-ref:引入其他命名空间的二级缓存
- resultMap:映射结果集规则,是最复杂最强大的元素。
- sql:sql语句块,供其他sql语句引入
- select:查
- insert:曾
- update:改
- delete:删
5.2.1 select元素
id | 它和Mapper的命名空间组合起来是唯一的,提供给MyBatis调用 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。 |
resultMap | 外部 resultMap 的命名引用。resultMap可以给予我们自定义映射规则的机会(通过id引用在映射文件中定义的resultMap)。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 设置超时时间,超时之后抛出异常,秒 (依赖驱动)。 |
fetchSize |
这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。 |
<!-- resultType="User" User 是完全限定名的别名 -->
<select id="selectByKey" resultType="User" parameterType="java.lang.Integer">
<!-- sql 语句 -->
where id = #{id,jdbcType=INTEGER}
</select>
select自动映射,使用resultType="类的完全限定名"
SQL的列名(sql字段可设置别名)和javaBean的属性名称一致,开启自动映射:autoMappingBehavior设置为PARTIAL或者FULL。
或者:autoMappingBehavior设置为PARTIAL或者FULL + mapUnderscoreToCamelCase设置为ture,可以把数据库的下划线命名规则自动改成驼峰规则进行映射。
实际开发过程中建议使用resultMap,自定义映射规则:解耦、易维护。
select 传参:
1、使用Map传递参数,不建议使用:因为不知道map中到底封入了哪些参数。
接口:
List<TUser> selectByEmailAndSex1(Map<String, Object> param);
对应的xml:
<select id="selectKey" resultType="User" parameterType="java.util.Map">
sql 语句
</select>
2、使用注解传递参数,直观明了,如果参数太多时不建议使用
接口
List<TUser> selectBySymbol(@Param("tableName")String tableName,
@Param("inCol")String inCol);
xml:
<select id="selectByKey" resultType="User"> // 不需要指定parameterType 了
sql 语句
</select>
3、使用Java Bean 传递参数
接口:
int update(TUser record);
5.2.2 resultMap
ResultMap 的设计思想:简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。
属性:
id:当前命名空间中的一个唯一标识,用于标识一个result map.
type:类的完全限定名, 或者一个类型别名。
autoMapping:如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属 性会覆盖全局的属性 autoMappingBehavior。默认值为:unset
子元素:
constructor - 用于在实例化类时,注入结果到构造方法中。(如果不加constructor,默认使用无参构造,若类没有无参构造,会报错)
• idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
• arg - 将被注入到构造方法的一个普通结果
<resultMap id="BaseResultMap" type="User">
<constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor>
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
......
</resultMap>
1、一个pojo不存在没有参数的构造方法,就需要使用constructor;
2、为了通过名称来引用构造方法参数,可以添加 @Param 注解,指定参数名称的前提下,以任意顺序编写 arg 元素(否则要按照顺序)
id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
result – 注入到字段或 JavaBean 属性的普通结果
id & result 属性:
property:POJO中映射到列结果的字段或者属性。
column:SQL中的列名,或者是列的别名。
javaType:配置的Java的类;
jdbcType:配置的数据库的类型;
typeHandler:类型处理器,使用这个属性,你可以覆盖默认的类型处理器。这个属性值是一个类型处理器实现类的完全限定名,或者是类型别名。
id & result
id 和 result 都将一个列的值映射到一个简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段
两者之间的唯一不同是, id 表示的结果将是对象的标识属性,这会在比较对象实例时用到。
这样可以 提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候。
association –( 一对一关系 ) 一个复杂类型的关联;许多结果将包装成这种类型
• 嵌套结果映射 – 关联可以指定为一个 resultMap 元素,或者引用一个
collection –( 一对多关系 ) 一个复杂类型的集合
• 嵌套结果映射 – 集合可以指定为一个 resultMap 元素,或者引用一个
discriminator – 使用结果值来决定使用哪个 resultMap
• case – 基于某些值的结果映射
° 嵌套结果映射 – 一个 case 也是一个映射它本身的结果,因此可以包含很多相同的元素,或者它可以参照外部的
<resultMap id="report" extends="BaseResultMap" type="User">
<discriminator column="sex" javaType="int">
<case value="1" resultMap="****"/>
<case value="2" resultMap="****2"/>
</discriminator>
</resultMap>
定义resultMap:
<resultMap id="BaseResultMap" type="User">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
......
</resultMap>
使用resultMap
<select id="select" resultMap="BaseResultMap"
parameterType="map">
<!-- sql 语句 -->
</select>
5.2.2 insert, update 和 delet
id:命名空间中的唯一标识符,可被用来代表这条语句。
parameterType:将要传入语句的参数的完全限定类名或别名。
flushCache:将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、 更新和删除语句)。
timeout:超时时间。
statementType:STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys:(仅对 insert 和 update 有用)使用 JDBC 的 getGeneratedKeys 方法取出由数据库内部生成的主键,默认值:false。
keyProperty:(仅对 insert 和 update 有用)对应数据库主键的POJO属性。MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn:(仅对 insert 和 update 有用)数据库主键。通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必 须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
databaseId:如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带 或者不带的语句都有,则不带的会被忽略。
5.2.3 selectKey元素
查找并且返回数据库生成的主键。
keyProperty:对应数据库主键的POJO 字段。selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn:数据库主键字段。匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType:返回的主键结果类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用 作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。
order:这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插 入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入 语句内部可能有嵌入索引调用。
statementType:与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。
<insert id="insert2" parameterType="TUser">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select
LAST_INSERT_ID()
</selectKey>
<!-- insert sql 语句 -->
</insert>
5.2.4 sql元素和参数
sql元素:用来定义可重用的 SQL 代码段,可以包含在其他语句中;
参数:向sql语句中传递的可变参数
预编译 #{}:将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,能够很大程度防止 sql注入;
传值 ${}:传入的数据直接显示生成在sql中,无法防止sql注入;
表名、选取的列是动态的,order by和in操作, 可以考虑使用$
定义代码段:
<sql id="Base_Column_List">
id, user_name, real_name, sex, mobile, email, note,
position_id
</sql>
使用代码段:
<select id="selectByPrimaryKey" resultMap="BaseResultMap"
parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from user
where id = #{id,jdbcType=INTEGER}
</select>
5.3 注解方式配置
注解方式就是将SQL语句直接写在接口上,对于需求比较简单的系统,效率较高。缺点在于,每次修改sql语句 都要编译代码,对于复杂的sql语句可编辑性和可读性都差,一般不建议使用这种配置方式;
@Select;@Results;@Insert; @Update; @Delete
5.4 动态sql元素
if:判断语句,单条件分支判断
choose、when、otherwise:相当于java的case when,多条件分支判断
Trim、where、set:辅助元素,用于处理sql拼装问题
foreach:循环语句,在in语句等列举条件常用,常用于实现批量操作
除开使用动态sql的foreach 做批量操作外,还可以使用BATCH类型的excutor。