MyBatis系列(一)——MyBatis的介绍和CRUD
前言
MyBatis是一个第三方开发的一款优秀的持久层框架,它不仅解决了原始JDBC操作数据库的繁琐步骤,而且还提供了自定义 SQL、存储过程以及高级映射等功能来简化我们的开发。当前MyBatis已经成为了许多项目的选择使用的持久层框架,作为一个java开发人员,掌握和清楚Mybatis的使用和原理是很有必要的。本篇文章将作为MyBatis系列的首篇,来介绍MyBatis的产生背景和基本的CRUD操作,希望能给各位读者一个参考。
想要了解更多MyBaits系列文章,可以从下面的传送门阅读:
MyBatis系列(二)——MyBatis的动态代理和映射文件动态配置
一、MyBatis的介绍
(一)MyBatis的产生背景
我们在前面的文章中曾经提到,java虽然给数据库厂商提供了操作数据库的接口,但原始的JDBC操作步骤还是十分的繁琐,需要我们手动写很多代码,这就引出了JDBC Template
工具的出现来简化我们的开发,MyBatis
也是在这种背景下产生的产物,但它比JDBC Template
、DBUtils
等工具类不同的是,它支持的功能更加强大、更丰富,所以也成为了许多项目持久层框架的选择。
口说无凭,下面我们就以常规的查询操作,来看一下原始的JDBC操作是什么样的吧
/**
* 该类用于演示使用JDBC原始API操作数据库案例
*/
public class JdbcForSqlTest {
public static User getUserById() throws Exception{
// 注册mysql驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取jdbc连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root.");
// 传入sql语句,获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from user where uid = ?");
// 传入参数
preparedStatement.setString(1,"1");
// 执行sql
ResultSet resultSet = preparedStatement.executeQuery();
// 将resultSet 拆分为具体的对象
User user = new User();
while (resultSet.next()){
user.setUid(resultSet.getInt("uid"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
}
// 释放资源
resultSet.close();
preparedStatement.close();
connection.close();
return user;
}
public static void main(String[] args) throws Exception {
System.out.println(getUserById());
}
}
我们从上面的代码中可以发现,原始的JDBC操作有着以下三个缺点:
1. 没有线程池的概念,每次执行sql都要获取和销毁数据库连接资源,浪费系统资源
2. sql语句没有实现解耦合,比如数据库的配置和sql语句都耦合在了代码上面,一旦配置或者sql语句需要变动,就要改java代码,而且也不方便复用。
3. 操作繁琐 查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置.
那么,针对这些问题,MyBatis提出了以下的解决方案:
- 使用数据库连接池初始化连接资源
- 将sql语句和数据库配置抽取到xml配置文件中
- 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
(二)MyBaits的简单演示Demo
下面我们来简单演示一下同样的需求,使用MyBatis是怎么样解决的:
1. 引入MyBatis依赖
如果已经引入了驱动包的话这里就只需要引入MyBatis
坐标就行
<!-- 引入mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- 引入mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
2. 将数据库配置抽取为jdbc.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
3. 创建UserMapper.xml文件
UserMapper.xml
用于存放我们抽取出来的sql语句
<?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="userMapper">
<select id="getUserById" parameterType="java.lang.Integer" resultType="com.qiqv.pojo.User">
select * from user where uid = #{id}
</select>
</mapper>
这里需要注意的有两点:
-
mapper
标签中的namespace
属性,表示这个文件主要封装了哪个实体类的sql语句,我们需要保证每个mapper.xml
文件的这个属性唯一。 -
select
标签表示该标签下的是select
查询语句
4. 创建MyBatis核心配置文件sqlMapConfig.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>
<!-- 获取jdbc.properties -->
<properties resource="jdbc.properties" ></properties>
<!-- 配置源环境 -->
<environments default="developement">
<environment id="developement">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<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="com/qiqv/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
在这个配置文件中,我们引入了jdbc.properties
文件和UserMapper.xml
,同时在enviroment
标签中配置了事务管理器为JDBC
,使用MyBatis的数据库连接池。
5. 编写实际的sql代码
public class MyBatisForSqlTest {
public static User getUserById() throws IOException {
// 将核心配置文件转为流对象
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
// 创建sqlSessionFactoryBuild对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 获取连接对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行sql语句
List<User> user = sqlSession.selectList("userMapper.getUserById", 1);
// 关闭资源
sqlSession.close();
return user.get(0);
}
public static void main(String[] args) throws IOException {
System.out.println(getUserById());
}
}
我们可以看到,使用MyBatis
之后,我们的结果集和参数的数据封装、sql和数据库的配置参数、数据库连接池的问题就都得到了解决。看起来似乎我们做多了很多步骤,但实际上当MyBaits
的框架搭好后,我们后面开发起来就不需要这么麻烦了。
二、MyBatis的配置文件概述
(一)映射文件
在第一节中,我们使用了UserMapper.xml
来封装我们的sql语句,下面我们就对这个配置文件来做一下基本的介绍吧。除开xml文件的约束头之外,我们日常开发中基本上都是在mapper
标签中添加和修改各式的sql语句,根据不同类型的sql语句,对应也有着select
、update
、insert
、delete
标签使用。
同时,虽然映射文件没有强制的命名规范,但我们一般还是会按照 pojo对象名 + Mapper.xml
的命名规则来定义映射文件
(二)核心配置文件
1. MyBatis核心配置文件层级关系
2. MyBatis常用配置解析
2.1 environments标签
MyBaits
允许我们在environments
标签中定义多套环境,比如开发环境、测试环境等,我们可以根据需要修改选择运行环境。
其中,事务管理器(transactionManager)类型有两种:
JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
其中,数据源(dataSource)类型有三种:
UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。(相当于没用连接池)
POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
2.2 mapper标签
该标签的作用是加载映射文件的,加载方式有如下几种:
- 使用相对于类路径的资源引用,例如:
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
- 使用完全限定资源定位符(URL),例如:
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
- 使用映射器接口实现类的完全限定类名,例如:
<mapper class="org.mybatis.builder.AuthorMapper"/>
- 将包内的映射器接口实现全部注册为映射器,例如:
<package name="org.mybatis.builder"/>
我们一般使用第一种和第四种方式比较多
2.3 Properties标签
实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件
2.4 typeAlias标签
见名知义,typeAlias标签的作用是设置别名。我们在第一节的例子的映射文件中,使用了resultType
和paramterType
两个属性来定义结果类型和返回值类型,我们需要填入对应类的全路径包名
但每次都要写类的全路径十分麻烦,别名的存在就帮我们解决了这个问题
在
MyBaits
中,已经帮我们定义好了一些常用的别名
别名 | 数据类型 |
---|---|
string | String |
long | Long |
int | lnteger |
double | Double |
boolean | Boolean |
... | ... |
我们也可以在核心配置文件中定义我们自己的别名
<!-- 配置别名 -->
<typeAliases >
<typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
</typeAliases>
这样我们原先映射文件中的sql标签就可以使用别名了
三、MyBatis的CRUD操作
(一)新增操作
映射文件中新增sql语句
<insert id="insertUser" parameterType="user">
insert into user values (#{uid},#{username},#{password})
</insert>
java代码如下:
public class UserDaoImpl implements UserDao {
public boolean addUser(User user) throws IOException {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = factory.openSession();
int result = sqlSession.insert("userMapper.insertUser",user);
System.out.println(result);
sqlSession.commit();
sqlSession.close();
return result>0;
}
}
这里需要注意的是,如果没有开启自动提交事务的话,需要手动执行commit
方法
(二)修改操作
映射文件中新增sql语句
<update id="updateUser" parameterType="user">
update user set username = #{username} where uid=#{uid};
</update>
java代码如下:
public class UserDaoImpl implements UserDao {
public boolean updateUser(User user)throws Exception {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = factory.openSession();
int result = sqlSession.update("userMapper.updateUser",user);
sqlSession.commit();
sqlSession.close();
return result>0;
}
}
(三)删除操作
映射文件中新增sql语句
<delete id="delUser" parameterType="int">
delete from user where uid=#{id};
</delete>
java代码如下:
public class UserDaoImpl implements UserDao {
public boolean deleteUser(Integer uid)throws Exception {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = factory.openSession();
int result = sqlSession.delete("userMapper.delUser",uid);
sqlSession.commit();
sqlSession.close();
return result>0;
}
}
(四)查询操作
映射文件中新增sql语句
<select id="getAllUser" resultType="user">
select * from user
</select>
java代码如下:
public class UserDaoImpl implements UserDao {
public List<User> getAllUser() throws Exception {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = factory.openSession();
List<User> users = sqlSession.selectList("userMapper.getAllUser");
System.out.println(users);
sqlSession.close();
return users;
}
}
至此,本篇文章中我们对MyBatis的入门介绍已经结束了,实际上MyBaits的入门操作并不难。我们在开发过程中遇到的问题往往也不仅仅是简单的单表操作,MyBaits的还有许多方法来帮助我们更好地解决DAO层的问题,想要了解更多可以参考本系列的其他文章。