Mybatis 入门篇 --手把手教你使用 Mybatis 操作数据库

iBit程序猿 2020年06月18日 1,673次浏览

安装 Mybatis

  • 将 mybaits-x.x.x.jar 文件置于 classpath 中。
  • 使用maven,则需要下述依赖
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

前置初始化数据

创建表

create table person (
  person_id int generated by default as identity(start with 1, increment by 1),
  person_name varchar(32),
  nick_name varchar(32),
  title varchar(16),
  age int,
  company_id int,
  primary key(person_id)
);

初始化数据

insert into person(person_name, nick_name, title, age, company_id) values ('张三', '小三', '后端', 28, 1);
insert into person(person_name, nick_name, title, age, company_id) values ('李四', '小四', '前端', 25, 1);
insert into person(person_name, nick_name, title, age, company_id) values ('王五', '小五', 'CTO', 31, 1);
insert into person(person_name, nick_name, title, age, company_id) values ('陆六', '小陆', '产品', 23, 2);
insert into person(person_name, nick_name, title, age, company_id) values ('柒七', '小柒', '测试', 20, 2);
insert into person(person_name, nick_name, title, age, company_id) values ('巴八', '小巴', '运维', 26, 3);

步骤

使用 Mybatis 操作数据库,主要由以下步骤组成

  • 构建 SqlSessionFactory 实例
  • 定义 Java 实体与数据库表建立映射
  • 定义用于执行 SQL 的 Mapper
  • 获取 SqlSession 实例,并执行相关的 SQL 语句

构建 SqlSessionFactory 实例

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

通过 XML 构建 SqlSessionFactory实例

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。简单例子 classpath:/mybatis-config.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>
    <settings>
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <environments default="test" >
        <environment id="test">
            <transactionManager type="JDBC">
                <property name="" value="" />
            </transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="org.hsqldb.jdbcDriver" />
                <property name="url" value="jdbc:hsqldb:mem:mybatis-test" />
                <property name="username" value="sa" />
                <property name="password" value="" />
            </dataSource>
        </environment>
    </environments>

	 <!--mapper定义完再配置上去-->
    <mappers>
        <mapper resource="tech/ibit/mybatis/learning/first/demo/mapper/PersonMapper.xml"/>
    </mappers>
</configuration>

读取 mybatis-config.xml 构建 SqlSessionFactory

try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
    // 通过SqlSessionFactoryBuilder的build()方法创建SqlSessionFactory实例
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

详细的 XML 配置可以参考 XML 配置

通过 Configuration 实例构建 SqlSessionFactory 实例

构造 Configuration 实例

// datasource
DataSource dataSource = new UnpooledDataSource("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:mybatis-test", "sa", "");

// xml 对应 transactionManager
TransactionFactory transactionFactory = new JdbcTransactionFactory();

// xml 对应 <environment>
Environment environment = new Environment("test", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);

// xml 对应 <settings> 
configuration.setUseGeneratedKeys(true);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setLogImpl(Log4jImpl.class);

// xml 对应 <mappers> 下 <mapper>
configuration.addMapper(PersonMapper.class);

构造 SqlSessionFactory 实例

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

注意: configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射注解从而避免依赖 XML 文件。

定义 Java 实体与数据库表建立映射

public class Person {
    private Integer personId;
    private String personName;
    private String nickName;
    private String title;
    private Integer age;
    private Integer companyId;
    // 省略 getter/setter 
}    

定义用于执行 SQL 的 Mapper

Mapper 配置主要分两部分

  • 定义 Mapper 接口
  • 通过 XML 或 注解的方式配置 SQL 语句

定义 Mapper 接口

public interface PersonMapper {
	// ...
}

通过 XML 或 注解的方式配置 SQL 语句

方式1:通过 XML 配置 SQL 语句

PersonMapper.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="tech.ibit.mybatis.learning.first.demo.mapper.PersonMapper">

    <sql id="allColumns">
        person_id, person_name, nick_name, title, age, company_id
    </sql>
    
    <!--列举所有人-->
    <select id="listAllPersons" resultType="tech.ibit.mybatis.learning.first.demo.entity.Person">
        select
        <include refid="allColumns"/>
        from person;
    </select>

</mapper>

在 PersonMapper.java 中增加与 id 同名的方法 listAllPersons:

List<Person> listAllPersons();

详细配置,可参考 XML 映射器

方式2:通过注解的方式配置 SQL 语句

PersonMapper.java 定义 getPersonById

@Select("select * from person where person_id=#{personId,jdbcType=INTEGER}")
Person getPersonById(@Param("personId") Integer personId);

详细的注解,可以参考 Java API

注意:
Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它(在这个例子中,基于类路径和 PersonMapper.class 的类名,会加载 PersonMapper.xml)。

获取 SqlSession 实例,并执行相关的 SQL 语句

获取 SqlSession 实例:

try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
	// 相关逻辑代码
}

使用 SqlSession 实例执行 SQL 语句有以下两种方式:

  • 直接通过 SqlSession 实例执行
  • 通过获取 Mapper 实例, 然后使用 Mapper 实例执行

示例代码:

// 通过 SqlSession 实例执行
Person person = sqlSession.selectOne("tech.ibit.mybatis.learning.first.demo.mapper.PersonMapper.getPersonById", 1);

// 等价代码:获取 Mapper 实例,然后通过 Mapper 实例执行
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
person = personMapper.getPersonById(1);

其他说明

完整代码请从 mybatis-learning/first-demo 获取。

理解作用域(Scope)和生命周期

理解我们之前讨论过的不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
  // ...
}

参考资料:

Mybatis 入门