Mybatis

接口层
与数据库的交互方式API
传统API
传统的传递Statement Id 和查询参数给 SqlSession 对象,使用 SqlSession对象完成和数据库的交互;
MyBatis提供了非常方便和简单的API,供用户实现对数据库的增删改查数据操作,以及对数据库连接信息和MyBatis 自身配置信息的维护操作。 
Mapper接口
MyBatis 将配置文件中的每一个<mapper> 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟<mapper> 节点中的<select|update|delete|insert> 节点项对应;
即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,
而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。

根据MyBatis 的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个Mapper 实例; 我们使用Mapper 接口的某一个方法时,MyBatis 会根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过SqlSession.select(“statementId”,parameterObject); 或者SqlSession.update(“statementId”,parameterObject); 等等来实现对数据库的操作
MyBatis 引用Mapper 接口这种调用方式,纯粹是为了满足面向接口编程的需要。 (其实还有一个原因是在于,面向接口的编程,使得用户在接口上可以使用注解来配置SQL语句,这样就可以脱离XML配置文件,实现“0配置”)。
数据处理层
-
数据处理层是Mybatis的核心 · 通过传入参数构建动态SQL; · SQL语句的执行以及封装查询结果集成List
-
动态 · MyBatis 通过传入的参数值,使用 Ognl 来动态地构造SQL语句,使得MyBatis 有很强的灵活性和扩展性。 · 参数映射指的是对于java 数据类型和jdbc数据类型之间的转换:这里有包括两个过程:查询阶段,我们要将java类型的数据,转换成jdbc类型的数据,通过 preparedStatement.setXXX() 来设值;另一个就是对resultset查询结果集的jdbcType 数据转换成java 数据类型。
-
SQL语句的执行以及封装查询结果集成List
· 动态SQL语句生成之后,MyBatis 将执行SQL语句,并将可能返回的结果集转换成List 列表。MyBatis 在对结果集的处理中,支持结果集关系一对多和多对一的转换,并且有两种支持方式,一种为嵌套查询语句的查询,还有一种是嵌套结果集的查询。
Mybatis核心部件
· SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
· Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
· StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
· ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
· ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
· TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
· MappedStatement MappedStatement维护了一条<select|update|delete|insert>节点的封装,
· SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
· BoundSql 表示动态生成的SQL语句以及相应的参数信息
· Configuration MyBatis所有的配置信息都维持在Configuration对象之中。

The code
Maven依赖
<?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>org.sukbear.www</groupId>
<artifactId>java-se</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.3</version>
</dependency>
</dependencies>
<build>
<!-- 定义classpath -->
<resources>
<!-- resources文件 -->
<resource>
<directory>src/main/resources</directory>
<!-- 是否被过滤,如果被过滤则无法使用 -->
<filtering>false</filtering>
</resource>
<!-- java文件夹 -->
<resource>
<directory>src/main/java</directory>
<!-- 引入映射文件等 -->
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
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>
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<!--<package name="tk.mybatis.simple.model"></package>-->
<package name="test.model"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="mysql"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 引入Mapper.xml -->
<!-- 用package的前提是对包下的接口,循环按接口限定名tk.mybatis.simple.mapper.UserMapper
转换成tk/mybatis/simple/mapper/UserMapper.xml 然后以.xml后缀搜索XML资源 ,找到就解析。-->
<!-- <mapper resource="tk/mybatis/simple/mapper/UserMapper.xml"/>
<mapper resource="tk/mybatis/simple/mapper/DynamicMapperTest.xml"/>-->
<!-- <mapper resource="test/xml/SysUserMapper.xml"/>-->
<package name="tk.mybatis.simple.mapper"/>
</mappers>
</configuration>
POJO
package tk.mybatis.simple.model;
import java.util.Date;
import java.util.List;
/**
* user
*
* @author sukbear
* @create 2018-12-10 16:21
*/
public class SysUser {
private Long id;
private String userName;
private String userPassword;
private String userEmail;
private String userInfo;
private byte[] headImg;
private Date createTime;
private SysRole role;
private List<SysRole> roleList;
public Long getId() {
return id;
}
public List<SysRole> getRoleList() {
return roleList;
}
public void setRoleList(List<SysRole> roleList) {
this.roleList = roleList;
}
public SysRole getRole() {
return role;
}
public void setRole(SysRole role) {
this.role = role;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserInfo() {
return userInfo;
}
public void setUserInfo(String userInfo) {
this.userInfo = userInfo;
}
public byte[] getHeadImg() {
return headImg;
}
public void setHeadImg(byte[] headImg) {
this.headImg = headImg;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
/* @Override
public String toString() {
return this.id+" "+this.userName;
}*/
}
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="tk.mybatis.simple.mapper.UserMapper">
<!--建立对象和属性的对应关系-->
<resultMap id="userMap" type="tk.mybatis.simple.model.SysUser">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<result property="userEmail" column="user_email"/>
<result property="userInfo" column="user_info"/>
<result property="headImg" column="head_img" jdbcType="BLOB"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>
<resultMap id="roleMap" type="tk.mybatis.simple.model.SysRole">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
<result property="enabled" column="enabled"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 返回类型为对象 -->
<!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
<select id="findUserByID" parameterType="int" resultType="tk.mybatis.simple.model.SysUser">
SELECT *
FROM sys_user
WHERE id = #{id}
</select>
<!-- 返回类型为之前定义的userMap -->
<!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
<select id="selectById" resultMap="userMap">
SELECT *
FROM sys_user
WHERE id = #{id}
</select>
<!-- #{对象的属性名} 用#号(不用$)可以预编译,避免sql注入 -->
<insert id="insert">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
<!--利用JDBC返回主键自增的值 {useGeneratedKeys="true"} -->
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
<!-- 使用selectKey返回主键的值 不同数据库selectKey不同 -->
<insert id="insert3">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT last_insert_id()
</selectKey>
</insert>
<select id="selectAll" resultMap="userMap">
SELECT *
FROM sys_user
</select>
<!-- -->
<select id="selectRolesByUserId" resultMap="roleMap">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime,
u.user_name AS "user.userName",
u.user_email AS "user.userEamil"
FROM sys_user u
INNER JOIN sys_user_role ur ON u.id = ur.user_id
INNER JOIN sys_role r ON ur.role_id = r.id
WHERE u.id = #{userId}
</select>
<!-- 根据id更新user的信息 -->
<update id="updateById">
UPDATE sys_user
SET
user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg,jdbcType=BLOB},
create_time = #{createTime,jdbcType=TIMESTAMP}
WHERE id = #{id}
</update>
<!-- 根据主键删除列 -->
<delete id="deleteById">
DELETE FROM sys_user
WHERE id = #{id}
</delete>
<!-- 多个接口参数(param("userId"))-->
<!-- 给参数配置@param注解后 mybatis自动将参数封装成Map @param的值成为key 故在SQL部分可以用配置的注解值来使用参数-->
<!--当参数时javaBean时要通过 对象.属性 比如 (@param("obj") Object obj) 在sql使用的时候就是obj.properties -->
<select id="selectRolesByUserIdAndRoleEnabled" resultType="tk.mybatis.simple.model.SysRole">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime
FROM sys_user u
INNER JOIN sys_user_role ur ON ur.user_id = u.id
INNER JOIN sys_role r ON ur.role_id = r.id
WHERE u.id = #{userId} AND r.enabled = #{enabled}
</select>
<select id="selectRolesByUserIdAndRoleEnabledUseJavaBean" resultType="tk.mybatis.simple.model.SysRole">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime
FROM sys_user u
INNER JOIN sys_user_role ur ON ur.user_id = u.id
INNER JOIN sys_role r ON ur.role_id = r.id
WHERE u.id = #{user.id} AND r.enabled = #{role.enabled}
</select>
</mapper>
对应接口
package tk.mybatis.simple.mapper;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.simple.model.SysRole;
import tk.mybatis.simple.model.SysUser;
import java.util.List;
/**
* usermapper
*
* @author sukbear
* @create 2018-12-10 16:31
*/
public interface UserMapper {
SysUser selectById(Long id);
int insert(SysUser sysUser);
int insert2(SysUser sysUser);
int insert3(SysUser sysUser);
List<SysUser> selectAll();
List<SysRole> selectRolesByUserId(Long userId);
int updateById(SysUser sysUser);
int deleteById(Long id);
List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);
List<SysRole> selectRolesByUserIdAndRoleEnabledUseJavaBean(@Param("user") SysUser user, @Param("role") SysRole role);
}
Test
- sqlSession基类(直接获取SqlSession)
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.BeforeClass;
import java.io.IOException;
import java.io.Reader;
/**
* provide sqlsession
*
* @author sukbear
* @create 2018-12-10 16:40
*/
public class BaseMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init() {
try {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;
import tk.mybatis.simple.mapper.UserMapper;
import tk.mybatis.simple.model.SysRole;
import tk.mybatis.simple.model.SysUser;
import java.util.Date;
import java.util.List;
/**
* test
*
* @author sukbear
* @create 2018-12-10 16:49
*/
public class UserMapperTest extends BaseMapperTest {
/* @Test
// 查询测试
public void testSelectById() {
SqlSession sqlSession = getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = userMapper.selectById(1L);
Assert.assertNotNull(user);
System.out.println(user.toString());
}*/
/* @Test
// 插入测试
public void insertTest() {
SqlSession sqlSession = super.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = new SysUser();
user.setUserName("test1");
user.setUserPassword("123456");
user.setUserEmail("test@123");
user.setUserInfo("testInfo");
user.setHeadImg(new byte[]{1, 2});
user.setCreateTime(new Date());
int result = userMapper.insert2(user);
Assert.assertEquals(1, result);
System.out.println(user.getId());
} finally {
sqlSession.rollback();
sqlSession.close();
}
}*/
/* @Test
public void selectAllTest() {
SqlSession sqlSession = super.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<SysUser> userList = userMapper.selectAll();
userList.stream().forEach(System.out::println);
List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
roleList.stream().forEach(System.out::println);
}
@Test
//关联查询测试
public void test() {
SqlSession sqlSession = super.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
roleList.stream().forEach(System.out::println);
}*/
/* //更新测试
@Test
public void updateByIdTest() {
SqlSession sqlSession = super.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = userMapper.selectById(1L);
user.setUserName("admin_test");
user.setUserEmail("admin@123");
int result = userMapper.updateById(user);
Assert.assertEquals(1, result);
Assert.assertEquals("admin_test", user.getUserName());
} finally {
sqlSession.rollback();
sqlSession.close();
}
}*/
//删除测试
/* @Test
public void deleteByIdTest(){
SqlSession sqlSession = super.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = userMapper.selectById(1L);
Assert.assertNotNull(user);
Assert.assertEquals(1,userMapper.deleteById(1L));
}finally {
sqlSession.rollback();
sqlSession.close();
}
}*/
@Test
public void selectRolesByUserIdAndRoleEnabledTest(){
SqlSession sqlSession = super.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = userMapper.selectById(1L);
SysRole role = new SysRole();
role.setEnabled(1);
List<SysRole> roleList = userMapper.selectRolesByUserIdAndRoleEnabledUseJavaBean(user,role);
Assert.assertNotNull(roleList);
}finally {
sqlSession.close();
}
}
}
参考
blog 书籍:Mybatis从入门到精通。