众所周知,在开发大多数系统的后台时,都能粗略地把任务分为表现交互层,业务服务层,数据持久层,Mybatis就是这样一个位于数据持久层的框架。经过一天的资料查阅,我准备将对它的认识记录在该博客中。
Mybatis框架的作用有:
Mybatis就是这样的一个框架。在它的官网,能获取到一些较为简单的介绍:http://www.mybatis.org/spring/zh/index.html
由于我是通过Maven项目使用的该框架,所以使用之前需要编写pom.xml文件:
<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.0modelVersion>
<groupId>org.datagroupId>
<artifactId>datatest1artifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-pluginartifactId>
<version>3.0.0version>
plugin>
<plugin>
<artifactId>maven-resources-pluginartifactId>
<version>3.0.2version>
plugin>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<version>3.7.0version>
plugin>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<version>2.20.1version>
plugin>
<plugin>
<artifactId>maven-jar-pluginartifactId>
<version>3.0.2version>
plugin>
<plugin>
<artifactId>maven-install-pluginartifactId>
<version>2.5.2version>
plugin>
<plugin>
<artifactId>maven-deploy-pluginartifactId>
<version>2.8.2version>
plugin>
plugins>
pluginManagement>
build>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.10version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.13version>
dependency>
dependencies>
project>
pom.xml文件中,最主要的依赖便是数据库驱动和mybatis了。定义好pom后,再编写mybatis本身所需要的配置文件,就可以快速开始了。
在写MyBatis的配置文件之前,我先理一理MyBatis中有哪些重要的组件,他们的生命周期是什么样的,以及为什么需要这个配置文件。相信看了下面,心中应该会有较为明确的答案。
MyBatis最重要的基础组件有:
SqlSessionFactoryBuilder: 结构化查询语言会话工厂构造器,该构造器将会读入Mybatis的xml配置文件或者设置好的Configuration对象来获得一个结构化查询语言会话工厂(SqlSessionFactory)。所以,通常在获取到工厂后它就没有其它作用了,也就是可以被销毁了。
SqlSessionFactory: 结构化查询语言会话工厂,该工厂用于获取结构化查询语言会话(SqlSession),也可以获取之前构造该工厂时的配置对象。由于该对象管理着数据库连接池,所以在一般情况下,对于同一个数据库实例,我们应该只创建一个静态最终的该对象。
SqlSession: 结构化查询语言会话,该对象用于和数据库的交互,即可以发送SQL也并返回结果,也可以获取映射接口的对象。相当于JDBC中的Connection对象。通过获取映射接口的对象可以通过方法调用来实现SQL的发送和返回。由于它只存在于数据库事务过程中,所以在事务执行完成后不需要使用它时,需要通过finally语句及时地保证正确地关闭它,否则将造成资源泄漏。
Mapper: 映射器,它是由一个Java接口和XML文件构成的对象(也可以由接口和注解组成),需要给出对应的SQL和映射规则,由SqlSession.getMapper(xxx.class)来得到它。它也可以负责发送SQL去执行并返回结果。和SqlSession是同级别的东西,只是用起来更加简单,可读。所以,它应该和它的会话保持同样的生命周期。以保证程序的正确运行与健壮。
在环境配置文件中,我们可以设置数据库连接池的配置,事务管理器的配置,还必须配置数据库驱动,连接地址以及账号和密码。以上这些东西组成一个 “环境” ,而MyBatis的环境配置文件可以配置多个环境。以方便在代码中获取该环境的会话工厂。如果需要使用该框架,最后还需要将映射配置到mappers标签中。
比较全面的环境配置示例和注释如下:
myBatisConfig.xml
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/javatest?
characterEncoding=utf8&serverTimezone=GMT&useSSL=FALSE"/>
<property name="username" value="xxxxxxxxxxxxx"/>
<property name="password" value="xxxxxxxxxxxxxx"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/xxx/xxxxxxx/UserMapper.xml">mapper>
<mapper resource="file:////var/mappers/com/xxxxx/xxxxx/UserMapper.xml">mapper>
<mapper class="com.xxxx.xxxxxx.UserMapper">mapper>
<package name="com.xxx.xxxxx.xxxx" />
mappers>
configuration>
需要注意的是,因为这里提供了多个设置属性的方法,所以它们是有优先级次序的:
通过方法参数传递的属性 > resource/url属性中指定的配置文件 > properties属性中指定的属性
在之前的文件里注册了一个映射文件,它的作用是定义数据库表和Java对象之间的映射,以及动静态SQL模版,结果集的定义等。由于映射文件的定义比较灵活,一个映射文件也不好演示所有的功能,所以下面的示例文件只演示了一些基本功能:
UserMapper.xml
<mapper namespace="org.mapper.UserMapper">
<resultMap id="userMap" type="org.data.User">
<id property="id" column="id" javaType="java.lang.Long">id>
<result property="name" column="name" javaType="java.lang.String">result>
<result property="contact" column="contact" javaType="java.lang.String">result>
<result property="telephone" column="telephone" javaType="java.lang.String">result>
<result property="email" column="email" javaType="java.lang.String">result>
<result property="remark" column="remark" javaType="java.lang.String">result>
<result property="photo" column="photo" javaType="java.lang.String">result>
resultMap>
<insert id="insertUser" keyProperty="id" useGeneratedKeys="true" parameterType="org.data.User">
insert into customer values(#{name},#{contact},#{telephone},#{email},#{remark},#{photo})
insert>
<delete id="deleteUser">
delete from customer where id = #{id}
delete>
<update id="updateUser">
update customer set id = #{user.id},name = #{user.name},contact=#{user.contact}
,telephone=#{user.telephone},email=#{user.email},remark=#{user.remark},photo=#{user.photo}
where id=#{id}
update>
<update id="updateUser2">
update customer set id = #{id},name = #{name},contact=#{contact},telephone=#{telephone}
,email=#{email},remark=#{remark},photo=#{photo}
where id=#{id}
update>
<select id="selectUserById" parameterType="int" resultType="org.data.User">
select * from customer where id=#{id}
select>
<select id="selectAllUser" resultMap="userMap">
select * from customer
select>
mapper>
Java映射接口为:
org.mapper.UserMapper
package org.mapper;
import org.apache.ibatis.annotations.Param;
import org.data.User;
import java.util.List;
public interface UserMapper {
/**
* 新增用户
* @param user
* @return
* @throws Exception
*/
public int insertUser(User user)throws Exception;
/**
* 修改用户
* @param user,id
* @return
* @throws Exception
*/
public int updateUser(@Param("user") User user,@Param("id") Long id)throws Exception;
/**
* 修改用户2
* @param user,id
* @return
* @throws Exception
*/
public int updateUser2(User user)throws Exception;
/**
* 删除用户
* @param id
* @return
* @throws Exception
*/
public int deleteUser(Long id)throws Exception;
/**
* 根据id查询用户
* @param id
* @return
* @throws Exception
*/
public int selectUserById(Long id)throws Exception;
/**
* 查询所有用户信息
* @return
* @throws Exception
*/
public List<User> selectAllUser()throws Exception;
}
以上的映射文件及接口则是MyBatis的核心功能了,但由于它的灵活,我没有将动态SQL写到这里,这里只介绍了一些基本的概念及用法。
在映射文件中,最重要的几个概念有:
parameterType:即参数类型,是我们传给Sql语句参数的类型,由于类型处理器的存在,所以SQL参数可以接受Java的基本类型以及引用类型,但需要定义他们之间的映射关系。由于MyBatis已经帮我们注册了Java的通用类型,并且还提供了默认的自动映射功能。所以大多数情况下我们并不需要填写该值。当然,在多参数的情况下是必须填写的。单参数情况下填写也有助于代码的可读性。
resultType:即结果类型,由于插入/更新/删除都是返回的操作成功的条目数,所以结果类型固定为int而不用改动,这里的结果类型参数是用于select标签中的属性,用于定义存储select语句获取的结果集。它也可以是内置的通用类型,也可以是我们定义的POJO,更强大的是还能存储在我们自定义的resultMap中。
resultMap:它是映射集的引用,可以执行强大的映射功能,我们在resultType和resultMap中选择一个作为查询结果的存储集,它能给我们一个自定义映射规则的机会。
在上面的例子中,演示了很多常用功能,比如主键回填,自定义并使用映射集,单参数和多参数的传参等等等。所以在这里我想介绍一下该映射文件的使用基础:
在编写以及使用映射文件的过程中,我们要牢记该文件的作用和职能,我们应该为它提供些什么?它又会为我们做哪些工作?只要弄清楚这些,我相信在编写映射时,你不再会为一些莫名其妙的错误感到疑惑。
映射文件 即是用于定义Java和SQL之间关系的文件,它需要一个Java接口用于接受和执行配置文件中的SQL语句,它需要将SQL语句需要的东西以Java的形式传入和返回。这是一个ORM映射文件最基本的东西。在高级功能中它还可以做到根据条件标签动态生成SQL语句,自定义复杂的映射集作为参数或返回集,以及原生SQLMS中有的功能(比如设置超时)和对它的优化(比如结果缓存)等等。
在这里只谈论最基本的功能,那便是将Java接口和SQL语句联系起来,以及Java类型和SQL类型的映射。
Java与SQL的联系
在上面的文件中,Java接口和映射xml组合起来表示一组映射关系,MyBatis通过配置文件中的mappers标签可以知道它们的存在。在实际使用中可以通过会话(SessionFactory产生的Session)获取该映射接口,然后通过接口的方法便可以调用SQL语句。
Java类型与SQL类型的映射
单参数映射
关于Java类型与SQL类型的关系映射,MyBatis主要通过类型注册来实现Java通用类型与SQL类型的映射关系(映射的定义),然后通过自动映射(映射的使用)就可以很方便的实现单参数的传参。自动映射要求表的列名和JavaBean的属性名称相同。如果数据库采用下划线方式命名,JavaBean采用驼峰式命名。则可以通过设置mapUnderscoreToCamelCase = true 来实现自动映射。
多参数映射1
对于多参数传参需要使用map
多参数映射2
或者使用@Param(“xxx”)注解接口参数的形式来手动指定映射,然后再进行传参。
多参数映射3
对于参数比较复杂的情况,以上两种方式可能都不太好。这时我们可以将SQL所需要的参数封装为一个JavaBean,这样一来就将多参数映射转换为了单映射的情况。
结果参数的映射
select语句的返回结果通常都是一个集,所以一般情况下可以用resultType属性来指定容纳这个集的类型,该类型可以是Java基本类型或引用类型。由于是单参数,所以MyBatis会自动帮我们实现自动映射。如果要求更为复杂的映射关系可以像上面那样通过自定义resultMap来实现复杂的映射引用。
Tips:在IDEA中,如果将映射mapper.xml文件放在src目录里,则Mybatis的配置文件会找不到该xml文件。如果是Maven项目可以加上这句话来解决:
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
includes>
resource>
resources>
build>
在本文中,提到了如下几点:
更为详细的配置文档:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeAliases