本笔记根据mybatis官方文档顺序学习,根据本笔记可快速掌握mybatis的使用。
使用MyBatis之前必须要安装mybatis-x.x.x.jar驱动文件到类路径中,如果使用的是Maven工程,则只需要导入下面的依赖即可:
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>x.x.xversion>
dependency>
每个MyBatis应用都需要围绕着SqlSessionFactory。一个SqlSessionFactory实例必须通过SqlSessionFactoryBuilder来创建。SqlSessionFactoryBuilder可以从XML配置文件中构建SqlSessionFactory实例,也可以从配置类中构建SqlSessionFactory实例。
从XML配置文件中构建SqlFactory实例非常简单。MyBatis包含一个工具类,叫做Resources,它包含许多方法,这些方法使从类路径和其他位置加载资源变得更简单。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
这个XML配置文件包含了MyBatis的核心配置,我们可以将它称作为MyBatis核心配置文件,这个核心配置包括获得数据库连接实例的数据源
(DataSource
),以及一个TransactionManager
,用于确定事务的范围和控制方式。这里有一个简单的示例:
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
mappers>
configuration>
虽然XML配置文件中还有许多内容,上面这个示例指出了配置文件中最重要的部分。请注意验证XML文档所需的XML头。environment
元素的主体包含用于事务管理和连接池(Dtype标签
)的环境配置。mappers元素包含一个映射器列表——包含SQL代码和映射定义的XML文件和/或带注解的Java接口类。(即对应的mapper映射文件)
已经有了SqlSessionFactory,可以获取实例SqlSession。SqlSession包含了对数据库执行SQL命令所需的所有方法。可以直接针对SqlSession实例执行映射的SQL语句。例如:
try (SqlSession session = sqlSessionFactory.openSession()) {
Account account = session.selectOne(
"com.xlb.mapper.AccountMapper.findById", 1);
}
虽然这种方法是有效的,并且对于MyBatis以前版本的用户来说很熟悉,但现在有了一种更清晰的方法。使用一个接口(例如BlogMapper.class)来正确地描述一个给定语句的参数和返回值,你现在可以执行更干净、更类型安全的代码,没有容易出错的字符串字面量和类型转换。例如:
try (SqlSession session = sqlSessionFactory.openSession()) {
AccountMapper mapper = session.getMapper(AccountMapper.class);
Account account= mapper.findById(1);
}
注意:上面这两种方法都可以获取到数据库中的数据,2.1.4的第一种方法通过findById来获取数据,其中第一个参数是需要调用的具体方法的字符串路径,第二个参数是给该方法传入的参数。通过这种方法可以直接获得实体数据。第二种方法是先通过session实例获得一个实体类的映射接口,然后通过这个接口来访问数据库中的数据。上面两种获取SqlSession的方法只需要掌握第二种即可。
MyBatis提供的全套功能可以通过使用基于XML的映射语言来实现,正是这种映射语言使MyBatis多年来非常流行。如果您以前使用过MyBatis,那么您将熟悉这个概念,但是对XML映射文档进行了许多改进,这些改进将在后面介绍。下面是一个满足上述SqlSession调用的基于XML的映射语句的例子。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xlb.mapper.AccountMapper">
<select id="findById" resultType="Account">
select * from tbl_account where id = #{id}
select>
mapper>
虽然对于这个简单的示例来说,这看起来开销很大,它实际上很轻。您可以在单个映射器XML文件中定义任意多的映射语句,这样就可以充分利用XML头和doctype声明. 文件的其余部分是不言自明的。它在名称空间中为映射语句“findById”定义了一个名称“com.xlb.mapper.AccountMapper”,允许你通过完整的限定名来调用该方法,正如我们在上面的例子中所做的那样:
Account account = session.findById(
"com.xlb.mapper.AccountMapper.findById", 1);
请注意,这与在完全限定的Java类上调用方法是多么相似,这是有原因的。该名称可以直接映射到与名称空间同名的Mapper类,并使用与名称、参数和返回类型匹配的方法作为映射的选择语句。这允许你非常简单地调用Mapper接口的方法,就像你在上面看到的那样,如下:
BlogMapper mapper = session.getMapper(AccountMapper.class);
Account account = mapper.findById(101);
第二种方法不依赖于字符串字面值,因此更安全。
准备一个数据库表:数据库叫mybatis,表叫tbl_account(数据库名和表明你随意叫)
# 创建数据库
create database mybatis;
# 创建数据库表
CREATE TABLE tbl_account(
id int primary key auto_increment,
name varchar(35),
money double
);
使用IDEA创建MyBatis项目
创建一个Maven项目
导入相关依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.xlbgroupId>
<artifactId>mybatisartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>jarpackaging>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>6.0.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.11version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.31version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
dependencies>
project>
创建数据库表对应的实体类
package com.xlb.domain;
public class Account {
private Integer id;
private String name;
private double money;
public Account(Integer id, String name, double money) {
this.id = id;
this.name = name;
this.money = money;
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
创建连接数据库时具体连接的哪个数据库信息的文件
jdbc.driver=com.mysql.cj.jdbc.Driver //数据库驱动
jdbc.url=jdbc:mysql://localhost:3306/mybatis //你连接的数据库名称
jdbc.username=root //你连接的数据库的用户名
jdbc.password=****** //你的数据库的密码
注:这个文件不是必须的,你也可以直接将这些信息写在MyBatis的核心配置文件中,只是将这些敏感信息额外保存到一个文件一方面容易管理,另一方面更加安全。
创建MyBatis的核心配置文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<typeAliases>
<package name="com.xlb.domain"/>
typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}">property>
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mappers/AccountMapper.xml" />
mappers>
configuration>
注意这个核心配置文件,你需要把上面package对应属性的路径改成自己的路径,mapper和properties标签对应的resource属性同样改成自己的路径。
创建mapper接口类
package com.xlb.mapper;
import com.xlb.domain.Account;
import java.util.List;
public interface AccountMapper {
//增删改查
void save(Account account);
void deleteById(Integer id);
void update(Account account);
Account findById(Integer id);
List<Account> findAll();
}
创建业务层接口
package com.xlb.service;
import com.xlb.domain.Account;
import java.util.List;
public interface AccountService {
//增删改查
void save(Account account);
void deleteById(Integer id);
void update(Account account);
Account findById(Integer id);
List<Account> findAll();
}
创建业务层实现
package com.xlb.service.impl;
import com.xlb.dao.AccountDao;
import com.xlb.domain.Account;
import com.xlb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class AccountImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public void deleteById(Integer id) {accountDao.deleteById(id);
}
@Override
public void update(Account account) {
}
@Override
public Account findById(Integer id) {
return accountDao.findById(id);
}
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
}
创建Mapper接口映射文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xlb.mapper.AccountMapper">
<select id="findById" resultType="Account">
select * from tbl_account where id = #{id}
select>
mapper>
创建main方法测试
import com.xlb.dao.AccountDao;
import com.xlb.domain.Account;
import com.xlb.mapper.AccountMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class main {
public static void main(String[] args) throws IOException {
test();
}
public static void test() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream in = Resources.getResourceAsStream("application.xml");
SqlSessionFactory sqlSessionFactory = builder.build(in);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
Account data = mapper.findById(1);
System.out.println(data);
}
}
在MyBatis的早期版本中,名称空间是可选的,这既令人困惑又没有帮助。
名称空间现在是必需的,它的目的不仅仅是用更长的、完全限定的名称隔离语句。
正如您在这里看到的那样,名称空间支持接口绑定,即使您认为现在不会使用它们,也应该遵循这里列出的这些实践,以防您改变主意。使用一次名称空间,并将其放在适当的Java包名称空间中,将清理代码并从长远来看提高MyBatis的可用性。
名称解析:为了减少键入的数量,MyBatis对所有命名的配置元素(包括语句、结果映射、缓存等)使用以下名称解析规则。
像BlogMapper这样的Mapper类还有一个技巧。它们的映射语句根本不需要用XML进行映射。相反,他们可以使用Java注解。例如,上面的XML可以删除并替换为:
public interface AccountMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Account findById(int id);
}
可以将AccountMapper.xml文件删除,然后使用如上所示注解,可以达到同样的效果(需要注意的是,因为将Mapper映射文件删除使用注解代替了,那么必须得扫描到该注解,所以需要在MyBatis核心配置文件中添加上该注解对应的包路径,也就是Mapper接口类的路径, 如下:)。
对于简单语句,注解要干净得多,然而,对于更复杂的语句,Java注解既有限又混乱。因此,如果必须处理复杂的事情,最好使用XML映射语句。这将取决于您和您的项目团队来决定哪一个适合您,以及以一致的方式定义映射语句对您来说有多重要。也就是说,你永远不会拘泥于单一的方法。您可以很容易地将基于注解的映射语句迁移到XML,反之亦然。
理解到目前为止我们讨论过的各种作用域和生命周期类是非常重要的。
不正确地使用它们会导致严重的并发问题。
这个类可以被实例化、使用和丢弃。一旦创建了SqlSessionFactory,就不需要保留它了。因此,SqlSessionFactoryBuilder实例的最佳作用域是方法作用域(即本地方法变量)。您可以重用SqlSessionFactoryBuilder来构建多个SqlSessionFactory实例,但是最好不要保留它,以确保所有的XML解析资源被释放出来用于更重要的事情。
一旦创建,SqlSessionFactory应该在应用程序执行期间一直存在。应该很少或根本没有理由处理它或重新创造它。最好的做法是不要重建在应用程序运行中多次使用SqlSessionFactory。因此,SqlSessionFactory的最佳作用域是应用程序作用域。这可以通过多种方式实现。最简单的是使用单例模式或静态单例模式。
每个线程都应该有自己的SqlSession实例。SqlSession的实例不能被共享,也不是线程安全的。因此,最好的作用域是请求或方法作用域。永远不要在静态字段甚至类的实例字段中保留对SqlSession实例的引用。永远不要在任何类型的托管范围(如Servlet框架的HttpSession)中保留对SqlSession的引用。
换句话说,在接收到HTTP请求时,可以打开SqlSession,然后在返回响应时关闭它。结束会议是非常重要的。您应该始终确保它在finally块中关闭。以下是确保SqlSessions关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
// do work
}
在整个代码中始终如一地使用此模式将确保正确关闭所有数据库资源。
映射器是为绑定到映射语句而创建的接口。映射器接口的实例是从SqlSession中获取的。因此,从技术上讲,任何mapper实例的最广泛范围与请求它们的SqlSession相同。然而,映射器实例的最佳作用域是方法作用域。也就是说,应该在使用它们的方法中请求它们,然后丢弃它们。它们不需要显式关闭。虽然与SqlSession类似,在整个请求过程中保留它们并不是问题,但您可能会发现在这个级别上管理太多的资源将很快失去控制。保持简单,将映射器保持在方法范围内。
下面的示例演示了这种做法。
try (SqlSession session = sqlSessionFactory.openSession()) {
AccountMapper mapper = session.getMapper(AccountMapper.class);
// do work
}
注:try后面跟着圆括号是JAVA7的新特性,圆括号可以声明,初始化一个或多个资源,此处的资源指得是那些必须在程序结束时必须关闭的资源(比如数据库连接,网络连接等),try语句在该语句结束时自动关闭这些资源。
注意:
- Mapper接口类的名字必须和Mapper映射文件的名字保持一致,例如本例中的Mapper接口叫做AccountMapper,本例中的Mapper映射文件叫做AccountMapper.xml
- MyBatis核心配置文件的名字没有固定要求,加载时指定你写的名字即可,一般可叫做mybatis-config.xml,application.xml等
- MyBatis的核心配置文件中设置扫描包路径时,如果使用的是resource标签,则需要使用目录对应的斜线
/
来指定目录层级,如果使用的是package属性,则需要使用.
来分开目录层级。