持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
本篇文章我们就来一起学习这一优秀的持久层框架——MyBatis。
MyBatis初体验
持久层框架当然是操作数据库了,为此,创建数据库和数据表:
CREATE DATABASE mybatis;
CREATE TABLE tbl_employee(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(255),
gender CHAR(1),
email VARCHAR(255)
);
INSERT INTO tbl_employee VALUES('tom',0,'tom@qq.com');
接下来我们创建一个maven项目,引入MyBatis的依赖:
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
接着创建数据表对应的Bean类:
@Data
@ToString
public class Employee {
private Integer id;
private String lastName;
private char gender;
private String email;
}
需要知道的是,每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
所以我们需要在类路径下编写一个XML文件(mybatis-config.xml)来完成SqlSessionFactory的构建:
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 注册Mapper映射文件 -->
<mappers>
<mapper resource="EmployeeMapper.xml"/>
</mappers>
</configuration>
该文件即为MyBatis的全局配置文件,用于配置MyBatis的一些功能,这里需要注意两点:首先是数据源的配置,然后是Mapper映射文件的注册,MyBatis的增删改查完全依赖于Mapper映射文件,所以我们还需要在类路径下编写Mapper映射文件(EmployeeMapper.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="com.wwj.mybatis.mapper.EmployeeMapper">
<select id="selectEmp" resultType="com.wwj.mybatis.bean.Employee">
select * from tbl_employee where id = #{id}
</select>
</mapper>
这里也需要注意几点, namespace 意为名称空间,主要起一个标识作用,可随意命名;其次是 <select> 标签,它表示的是一个查询操作,相应地,它还有 <insert> 、<delete> 、 <update> 标签分别用于插入、删除和更新;在 <select> 标签中指定了id和resultType属性,其中id仍然为一个标识符,resultType为本次查询得到的结果类型,MyBatis会自动将数据表中查询到的数据封装成该类型,最后在标签内编写sql语句即可, #{id} 能够取出传递过来的id值。
\
一切准备就绪后,我们就可以编写业务代码了:
@Test
public void test() throws IOException {
String resource = "mybatis-config.xml";
InputStream stream = Resources.getResourceAsStream(resource);
// 构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行sql
Employee employee = sqlSession.selectOne("selectEmp", 1);
System.out.println(employee);
}
通过全局配置文件构建sqlSessionFactory对象,并通过sqlSessionFactory获取sqlSession,调用selectOne方法即可查询到一个结果,第一个参数值为Mapper映射文件中操作标签的id值,为了避免重复引发的问题,一般以名称空间 + 操作标签id值为参数值: com.wwj.mybatis.mapper.EmployeeMapper.selectEmp ;第二个参数值会被MyBatis传递给sql,也就是说,第二个参数值1会被 #{id} 成功获取。
\
执行结果:
Employee(id=1, lastName=null, gender=0, email=tom@qq.com)
很显然,我们查询到了结果,然而会发现lastName属性值为空,这是为什么呢?
原来,JavaBean中的lastName与数据表中last_name字段不匹配,为了解决这一问题,我们可以重新编写一下sql语句:
select id,last_name lastName,gender,email from tbl_employee where id = #{id}
在查询的时候将字段重新设置属性名即可,不过MyBatis也考虑到了这一点,所以特地设置了一个全局属性,我们只需要开启它即可自动处理这一问题:
<settings>
<!-- 开启驼峰命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
在全局配置文件中设置开启驼峰命名即可,但需要注意,它只能处理遵守驼峰命名规范的属性,比如lastName和last_name,empSalary和emp_salary。
接口式编程
在刚才我们体验了一下MyBatis框架的简单查询,会发现这种方式存在着一些问题,比如操作标识过长、第二个参数因为是Object类型,也会出现很多错误,为此,MyBatis提供了更加优雅的解决方案——接口式编程。
\
我们改造一下刚才的程序,首先编写一个接口:
public interface EmployeeMapper {
Employee getEmpById(Integer id);
}
在该接口中我们可以声明各种操作方法而无需具体实现,比如通过id查询Employee,此时我们只需要稍加修改Mapper映射文件即可:
<?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.wwj.mybatis.mapper.EmployeeMapper">
<select id="getEmpById" resultType="com.wwj.mybatis.bean.Employee">
select * from tbl_employee where id = #{id}
</select>
</mapper>
首先将名称空间写为接口的全类名,此时该映射文件会与接口进行唯一绑定,此时 <select> 标签的id属性值就需要写为接口方法名,resultType为接口方法的返回值。
\
到这里就改造完成了,当然,我们的业务代码也发生了相应的变化:
@Test
public void test() throws IOException {
String resource = "mybatis-config.xml";
InputStream stream = Resources.getResourceAsStream(resource);
// 构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取Mapper接口的实现
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
// 调用方法
Employee employee = employeeMapper.getEmpById(1);
System.out.println(employee);
}
仍然需要构建sqlSessionFactory对象,并通过其获得sqlSession,此时通过sqlSession调用getMapper方法就能够获取到MyBatis为我们创建的接口实现类,此时通过该实现类即可调用方法完成查询。
\
执行结果:
Employee(id=1, lastName=tom, gender=0, email=tom@qq.com)