MyBatis 入门
什么是MyBatis
MyBatis 是当前主流的 ORM 框架,是由 Apache 提供的一个开源项目,之前的名字叫做 iBatis,2010 年迁移到了 Google Code,并且将名字改为我们现在所熟知的 MyBatis,又于 2013 年 11 月迁移到了 Github。MyBatis 是一个帮助开发者实现数据持久化工作的框架,它同时支持 Java、.NET、Ruby 三种语言的实现,当然我们这里讲的是在 Java Application 中的使用,初学者可以将 MyBatis 简单理解为一个对 JDBC 进行封装的框架。
说到 ORM 框架就不得不提 Hibernate,Hibernate 是实现了 JPA 规范的 ORM 框架,使用非常广泛,Spring Data JPA 底层就是采用 Hibernate 技术支持。同为 ORM 框架,MyBatis 与 Hibernate 的区别是什么呢?
Hibernate 是一个“全自动化”的 ORM 框架,而 MyBatis 则是一个“半自动化”的 ORM 框架。
什么是“全自动化”?意为开发者只需要调用相关接口就可以完成操作,整个流程框架都已经封装好了,开发者无需关注。具体来讲 Hibernate 实现了 POJO 和数据库表之间的映射,同时可以自动生成 SQL 语句并完成执行。
“半自动化”指的是框架只提供了一部分功能,剩下的工作仍需要开发者手动完成,MyBatis 框架没有实现 POJO 与数据库表的映射,它只实现了 POJO 与 SQL 之间的映射关系,同时需要开发者手动定义 SQL 语句,以及数据与 POJO 的装配关系。
虽然功能上没有 Hibernate 更加方便,但是这种“半自动化”的方式提高了框架的灵活性,MyBatis 对所有的 JDBC 代码实现了封装,包括参数设置、SQL 执行、结果集解析等,通过 XML 配置的方式完成 POJO 与数据的映射。
MyBatis 的优点
- 极大地简化了 JDBC 代码的开发
- 简单好用、容易上手,具有更好的灵活性
- 通过将 SQL 定义在 XML 文件中的方式降低呈现的耦合度
- 支持动态 SQL,可根据具体业务灵活实现需求
MyBatis 的缺点
- 相比于 Hibernate,开发者需要完成更多工作,如定义 SQL、设置 POJO 与数据的映射关系等
- 要求开发人员具备一定的 SQL 编写能力,在一些特定场景下工作量较大
- 数据库移植性较差,因为 SQL 依赖于底层数据库,如果要进行数据库迁移,部分 SQL 需要重新编写
整体来说,MyBatis 是一个非常不错的持久层解决方案,它专注于 SQL 本身,非常灵活,适用于需求变化较多的互联网项目,也是当前主流的 ORM 框架。
MyBatis 快速入门
(1)创建 Maven 工程,pom.xml 添加相关依赖,我们使用 MySQL 数据库,因此需要额外引入 MySQL 驱动依赖。为了在控制台上显示SQL语句,还需要引入log4j依赖。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
在resources目录下新建log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<!-- 将日志信息输出到控制台 -->
<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<!-- 设置日志输出的样式 -->
<layout class="org.apache.log4j.PatternLayout">
<!-- 设置日志输出的格式 -->
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss:SSS}] %m%n" />
</layout>
<!--过滤器设置输出的级别-->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<!-- 设置日志输出的最小级别 -->
<param name="levelMin" value="DEBUG" />
<!-- 设置日志输出的最大级别 -->
<param name="levelMax" value="ERROR" />
<!-- 设置日志输出的xxx,默认是false -->
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<!-- 根logger的设置-->
<root>
<appender-ref ref="ConsoleAppender"/>
</root>
</log4j:configuration>
(2)新建数据表
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(255) DEFAULT NULL,
user_email varchar(255) DEFAULT NULL,
user_city varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
PRIMARY KEY (id)
)
(3)创建user表对应的实体类
public class User {
private Integer id;
private String username;
private String userEmail;
private String userCity;
private Integer age;
// 省略get、set方法
}
(4)在 resources 路径下创建 MyBatis 配置文件mybatis- config.xml(文件名可自定义),配置数据源信息。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<!-- 配置 MyBatis 运行环境 -->
<environment id="development">
<!-- 配置 JDBC 事务管理 -->
<transactionManager type="JDBC"/>
<!-- POOLED 配置 JDBC 数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
(5)MyBatis 开发有两种方式:
- 使用原生接口
- Mapper 代理实现自定义接口
先来说第一种使用原生接口的开发方式。
第一步,在resources目录下创建mapper文件夹,并创建 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">
<!--
namespace: 命名空间, 如果有对应的接口,需要指定为对应接口的全类名, 如果使用原生接口, 则可以随便填写
id: 唯一标识
parameterType: 为参数数据类型,可以省略
resultType: 为返回值数据类型
#{username}是获取传递过来的参数中获取 username 的值
-->
<mapper namespace="com.example.mybatis.mapper.UserMapper">
<select id="getUserByUserName"
parameterType="java.util.String"
resultType="com.example.mybatis.entity.User">
select
id,
username,
user_email userEmail,
user_city userCity,
age
from user
where username = #{username}
</select>
</mapper>
第二步,在全局配置文件 mybatis-config.xml 中注册 UseMapper.xml。
<configuration>
<environments default="development">
<!-- 配置 MyBatis 运行环境 -->
<environment id="development">
<!-- 配置 JDBC 事务管理 -->
<transactionManager type="JDBC"/>
<!-- POOLED 配置 JDBC 数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 注册UserMapper.xml -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
第三步,在测试类中调用原生接口执行 SQL 语句获取结果。
public class App1 {
public static void main( String[] args ) {
// 加载 MyBatis 配置文件
InputStream is = App1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 调用 MyBatis 原生接口执行 SQL
// statement 为 UserMapper.xml 的 namespace 值+"."+select 标签的 id 值
String statement = "com.example.mybatis.mapper.UserMapper.getUserByUserName";
User user = sqlSession.selectOne(statement , "zhangsan");
// SqlSession的selectOne(String var1, Object var2)方法
// 可以发现第二个参数是Object类型的,
// 例子中我们只传递了一个参数, 如果想传入多个参数的话, 可以传递一个Map或者是一个实体类对象
System.out.println(user);
}
}
我们在实际开发中,推荐使用第二种方式:自定义接口,但是开发者不需要实现该接口,只需要定义即可,具体的实现工作由 Mapper 代理结合配置文件完成,实现逻辑或者说要执行的 SQL 语句配置在 Mapper.xml 中。
第一步,自定义接口
public interface UserMapper {
public User getUserByUserName(String userName);
public List<User> getUserList();
public int addUser(User user);
public int deleteUser(Integer id);
public int updateUser(User user);
}
第二步, 将UserMapper.xml中的namespace设置为UserMapper的全类名
<?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">
<!--
namespace: 命名空间, 如果有对应的接口,需要指定为对应接口的全类名, 如果使用原生接口, 则可以随便填写
id: 唯一标识
parameterType: 为参数数据类型,可以省略
resultType: 为返回值数据类型
#{username}是获取传递过来的参数中获取 username 的值
-->
<mapper namespace="com.example.mybatis.mapper.UserMapper">
<select id="getUserByUserName"
parameterType="String"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
<select id="getUserList"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
</select>
<insert id="addUser"
parameterType="com.example.mybatis.entity.User">
insert into user
(username, user_email, user_city, age)
values (#{username}, #{userEmail}, #{userCity}, #{age})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="com.example.mybatis.entity.User">
update user
set username=#{username}, user_email=#{userEmail}, user_city=#{userCity}, age=#{age}
where id=#{id}
</update>
</mapper>
UserMapper.xml 中 namespace 为接口的全类名
UserMapper.xml 中的 id 为接口中对应的方法名
UserMapper.xml 中的 parameterType 和接口中对应方法的参数类型一致
UserMapper.xml 中的 resultType 和接口中对应方法的返回值类型一致
第四步,测试。
public class App2 {
public static void main( String[] args ) {
// 加载 MyBatis 配置文件
InputStream is = App2.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 获取 SqlSession, 代表和数据库的一次会话, 用完需要关闭
// SqlSession 和Connection, 都是非线程安全的, 每次使用都应该去获取新的对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取实现接口的代理对象
// UserMapper 并没有实现类, 但是mybatis会为这个接口生成一个代理对象(将接口和xml绑定)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 1. 查询
User user = userMapper.getUserByUserName("zhangsan");
System.out.println(user.toString());
List<User> userList = userMapper.getUserList();
userList.stream().forEach(obj -> System.out.println(obj.toString()));
/*-------------------------------------------------------------------*/
// 2. 新增
User addUser = new User();
addUser.setUsername("lzc");
addUser.setUserEmail("lzc@qq.com");
addUser.setUserCity("深圳");
addUser.setAge(18);
userMapper.addUser(addUser);
sqlSession.commit(); // 提交事务
/*-------------------------------------------------------------------*/
// 3. 删除
userMapper.deleteUser(1);
sqlSession.commit(); // 提交事务
/*-------------------------------------------------------------------*/
// 4. 修改
User updateUser = new User();
updateUser.setId(4);
updateUser.setUsername("lizhencheng");
updateUser.setUserEmail("lizhencheng@qq.com");
updateUser.setUserCity("桂林");
updateUser.setAge(16);
userMapper.updateUser(updateUser);
sqlSession.commit(); // 提交事务
/*-------------------------------------------------------------------*/
sqlSession.close();
}
}
代码链接:https://github.com/923226145/MyBatis-learn...
本作品采用《CC 协议》,转载必须注明作者和本文链接