主要讲解 MyBatis 的基础知识,内容来源于《C 语言中文网》。
MyBatis示例
项目准备
DB使用的是Mysql,pom.xml需要添加的依赖包:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
DB结构:
CREATE TABLE `user_test` (
`uid` tinyint(2) NOT NULL,
`uname` varchar(20) DEFAULT NULL,
`usex` varchar(10) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DB初始数据:
uid | uname | usex |
---|---|---|
1 | 张三 | 女 |
2 | 陈恒 | 男 |
3 | 楼仔 | 男 |
具体示例
第一步:先创建持久化类:
@Data
public class MyUser {
private Integer uid; // 主键
private String uname;
private String usex;
}
第二步:创建映射文件
<?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.mybatis.dao.UserDao">
<!-- 根据uid查询一个用户信息 -->
<select id="selectUserById" parameterType="Integer" resultType="com.mybatis.entity.MyUser">
select * from user_test where uid = #{uid}
</select>
<!-- 查询所有用户信息 -->
<select id="selectAllUser" resultType="com.mybatis.entity.MyUser">
select * from user_test
</select>
<!-- 添加一个用户,#{uname}为 com.mybatis.po.MyUser 的属性值 -->
<insert id="addUser" parameterType="com.mybatis.entity.MyUser">
insert into user_test (uid,uname,usex)
values(#{uid},#{uname},#{usex})
</insert>
<!--修改一个用户 -->
<update id="updateUser" parameterType="com.mybatis.entity.MyUser">
update user_test set uname =#{uname},usex = #{usex} where uid = #{uid}
</update>
<!-- 删除一个用户 -->
<delete id="deleteUser" parameterType="Integer">
delete from user_test where uid= #{uid}
</delete>
</mapper>
第三步:创建 MyBatis 的配置文件
<?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="cacheEnabled" value="false"/>
<setting name="defaultExecutorType" value="REUSE"/>
<setting name="useGeneratedKeys" value="true"/>
</settings>
<!-- 配置mybatis运行环境 -->
<!-- 如果只启动mybatis,这里一定需要;如果通过spring使用mybatis,这里可以删掉,因为SQL的配置在src/main/resources/applicationContext.xml中 -->
<environments default="development">
<environment id="development">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- MySQL数据库驱动 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://xxx:xxx/xm_jointly?characterEncoding=utf8" />
<property name="username" value="jointly_xxx" />
<property name="password" value="G-uTlU-xxx" />
</dataSource>
</environment>
</environments>
<!-- 将mapper文件加入到配置文件中-->
<mappers>
<mapper resource="com/mybatis/mapper/UserMapper.xml" />
</mappers>
</configuration>
第四步:创建测试类
public class MyBatisTest {
public static void main(String[] args) {
try {
// 读取配置文件 mybatis-config.xml
InputStream config = Resources.getResourceAsStream("com/mybatis/config/datasources/mybatis-config.xml");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);
// 通过 SqlSessionFactory 创建 SqlSession
SqlSession ss = ssf.openSession();
// 查询一个用户
MyUser mu = ss.selectOne("com.mybatis.dao.UserDao.selectUserById", 1);
System.out.println(mu);
// 修改一个用户
MyUser updatemu = new MyUser();
updatemu.setUid(1);
updatemu.setUname("张三");
updatemu.setUsex("女");
ss.update("com.mybatis.dao.UserDao.updateUser", updatemu);
// 查询所有用户
List<MyUser> listMu = ss.selectList("com.mybatis.dao.UserDao.selectAllUser");
for (MyUser myUser : listMu) {
System.out.println(myUser);
}
// 提交事务
ss.commit();
// 关闭 SqlSession
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出:
MyUser(uid=1, uname=张三, usex=女)
MyUser(uid=1, uname=张三, usex=女)
MyUser(uid=2, uname=陈恒, usex=男)
MyUser(uid=3, uname=楼仔, usex=男)
项目整体结构:
配置文件详解
MyBatis 配置文件并不复杂,它所有的元素如下所示:
<?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 /><!-- 属性 -->
<settings /><!-- 设置 -->
<typeAliases /><!-- 类型命名 -->
<typeHandlers /><!-- 类型处理器 -->
<objectFactory /><!-- 对象工厂 -->
<plugins /><!-- 插件 -->
<environments><!-- 配置环境 -->
<environment><!-- 环境变量 -->
<transactionManager /><!-- 事务管理器 -->
<dataSource /><!-- 数据源 -->
</environment>
</environments>
<databaseIdProvider /><!-- 数据库厂商标识 -->
<mappers /><!-- 映射器 -->
</configuration>
但是需要注意的是,MyBatis 配置项的顺序不能颠倒。如果颠倒了它们的顺序,那么在 MyBatis 启动阶段就会发生异常,导致程序无法运行。
properties
properties 属性可以给系统配置一些运行参数,可以放在 XML 文件或者 properties 文件中,而不是放在 Java 编码中,这样的好处在于方便参数修改,而不会引起代码的重新编译。一般而言,MyBatis 提供了 3 种方式让我们使用 properties,它们是property 子元素、properties 文件和程序代码传递,这里我们只讲“property 子元素”的方式。
以下面代码为基础,使用 property 子元素将数据库连接的相关配置进行改写,这里可以直接参考“MyBatis示例”中的XML配置即可。
这里使用了元素 “properties” 下的子元素 “property” 定义,用字符串 database.username 定义数据库用户名,然后就可以在数据库定义中引入这个已经定义好的属性参数,如 ${database.username},这样定义一次就可以到处引用了。但是如果属性参数有成百上千个,显然使用这样的方式不是一个很好的选择,这个时候可以使用 properties 文件。
properties 文件的方式,这个很简单,主要就是将Mysql的相关配置信息放入xx.properties的配置文件中,后面讲述MyBatis和Spring整合时再介绍。
settings
在 MyBatis 中 settings 是最复杂的配置,它能深刻影响 MyBatis 底层的运行,但是在大部分情况下使用默认值便可以运行,所以在大部分情况下不需要大量配置它,只需要修改一些常用的规则即可,比如自动映射、驼峰命名映射、级联规则、是否启动缓存、执行器(Executor)类型等。
settings 的配置项很多,但是真正用到的不会太多,我们把常用的配置项研究清楚就可以了,比如关于缓存的 cacheEnabled,关于级联的 lazyLoadingEnabled 和 aggressiveLazy Loading,关于自动映射的 autoMappingBehavior 和 mapUnderscoreToCamelCase,关于执行器类型的 defaultExecutorType 等。
东西太多,我才不会挨个看,就挑几个重点的看看就行。
typeAliases
由于类的全限定名称很长,需要大量使用的时候,总写那么长的名称不方便。在 MyBatis 中允许定义一个简写来代表这个类,这就是别名,别名分为系统定义别名和自定义别名。在 MyBatis 中别名由类 TypeAliasRegistry(org.apache.ibatis.type.TypeAliasRegistry)去定义。注意,在 MyBatis 中别名不区分大小写。
这块感觉用的不多,我就先不详细了解,等要用的时候,我再回来看看那。
typeHandlers
在 JDBC 中,需要在 PreparedStatement 对象中设置那些已经预编译过的 SQL 语句的参数。执行 SQL 后,会通过 ResultSet 对象获取得到数据库的数据,而这些 MyBatis 是根据数据的类型通过 typeHandler 来实现的。
在 typeHandler 中,分为 jdbcType 和 javaType,其中 jdbcType 用于定义数据库类型,而 javaType 用于定义 Java 类型,那么 typeHandler 的作用就是承担 jdbcType 和 javaType 之间的相互转换。在很多情况下我们并不需要去配置 typeHandler、jdbcType、javaType,因为 MyBatis 会探测应该使用什么类型的 typeHandler 进行处理,但是有些场景无法探测到。对于那些需要使用自定义枚举的场景,或者数据库使用特殊数据类型的场景,可以使用自定义的 typeHandler 去处理类型之间的转换问题。
系统提供的 typeHandler 能覆盖大部分场景的要求,但是有些情况下是不够的,比如我们有特殊的转换规则,枚举类就是这样。
同typeAliases,这块也用的不多,先不详细了解,留个记录,需要的话再回来看看。
objectFactory
当创建结果集时,MyBatis 会使用一个对象工厂来完成创建这个结果集实例。在默认的情况下,MyBatis 会使用其定义的对象工厂——DefaultObjectFactory(org.apache.ibatis.reflection.factory.DefaultObjectFactory)来完成对应的工作。
MyBatis 允许注册自定义的 ObjectFactory。如果自定义,则需要实现接口 org.apache.ibatis.reflection.factory.ObjectFactory,并给予配置。
在大部分的情况下,我们都不需要自定义返回规则,因为这些比较复杂而且容易出错,在更多的情况下,都会考虑继承系统已经实现好的 DefaultObjectFactory ,通过一定的改写来完成我们所需要的工作。
仅作了解即可,因为我们一般不会创建自己的“对象工厂”。
environments
在 MyBatis 中,运行环境主要的作用是配置数据库信息,它可以配置多个数据库,一般而言只需要配置其中的一个就可以了。它下面又分为两个可配置的元素:事务管理器(transactionManager)、数据源(dataSource),回归一下我们示例中的配置
<environments default="development">
<environment id="development">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- MySQL数据库驱动 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://xxx:xxx/xm_jointly?characterEncoding=utf8" />
<property name="username" value="jointly_xxx" />
<property name="password" value="G-uTlU-xxx" />
</dataSource>
</environment>
</environments>
在实际的工作中,大部分情况下会采用 Spring 对数据源和数据库的事务进行管理,这个会在下一篇文章“Spring和MyBatis整合”进行讲解。
transactionManager
在 MyBatis 中,transactionManager 提供了两个实现类,它需要实现接口 Transaction(org.apache.ibatis.transaction.Transaction),它的定义代码如下所示。
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
从方法可知,它主要的工作就是提交(commit)、回滚(rollback)和关闭(close)数据库的事务。MyBatis 为 Transaction 提供了两个实现类:JdbcTransaction 和 ManagedTransaction,如图 1 所示。
于是它对应着两种工厂:JdbcTransactionFactory 和 ManagedTransactionFactory,这个工厂需要实现 TransactionFactory 接口,通过它们会生成对应的 Transaction 对象。于是可以把事务管理器配置成为以下两种方式:
<transactionManager type="JDBC"/>
<transactionManager type="MANAGED"/>
这里做简要的说明:
-
JDBC 使用 JdbcTransactionFactory 生成的 JdbcTransaction 对象实现。它是以 JDBC 的方式对数据库的提交和回滚进行操作。
-
MANAGED 使用 ManagedTransactionFactory 生成的 ManagedTransaction 对象实现。它的提交和回滚方法不用任何操作,而是把事务交给容器处理。在默认情况下,它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
当然,你也可以定义自己的transactionManager,这里就不展开了。
environment
environment 的主要作用是配置数据库,在 MyBatis 中,数据库通过 PooledDataSource Factory、UnpooledDataSourceFactory 和 JndiDataSourceFactory 三个工厂类来提供,前两者对应产生 PooledDataSource、UnpooledDataSource 类对象,而 JndiDataSourceFactory 则会根据 JNDI 的信息拿到外部容器实现的数据库连接对象。
无论如何这三个工厂类,最后生成的产品都会是一个实现了 DataSource 接口的数据库连接对象。由于存在三种数据源,所以可以按照下面的形式配置它们。
<dataSource type="UNPOOLED">
<dataSource type="POOLED">
<dataSource type="JNDI">
论述一下这三种数据源及其属性:
-
UNPOOLED:UNPOOLED 采用非数据库池的管理方式,每次请求都会打开一个新的数据库连接,所以创建会比较慢。在一些对性能没有很高要求的场合可以使用它。
-
POOLED:数据源 POOLED 利用“池”的概念将 JDBC 的 Connection 对象组织起来,它开始会有一些空置,并且已经连接好的数据库连接,所以请求时,无须再建立和验证,省去了创建新的连接实例时所必需的初始化和认证时间。它还控制最大连接数,避免过多的连接导致系统瓶颈。
-
JNDI:数据源 JNDI 的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
欢迎大家多多点赞,更多文章,请关注微信公众号“楼仔进阶之路”,点关注,不迷路~~