- 开发我的第一个 Mybatis 程序:
将项目的打包方式设置为
jar
。引入依赖:
- mybatis 依赖
- mysql 驱动依赖
……
二、MyBatis入门程序
2.1 ★Mybatis入门程序开发步骤
开发我的第一个 Mybatis 程序:
将项目的打包方式设置为
jar
。引入依赖:
- mybatis 依赖
- mysql 驱动依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35<!-- pom.xml文件 -->
<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.0</modelVersion>
<groupId>com.f</groupId>
<artifactId>mybatis-001-introduction</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 打包方式jar -->
<packaging>jar</packaging>
<dependencies>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>编写mybatis核心配置文件:
mybatis-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 执行XxxMapper.xml文件的路径 -->
<!-- resource属性自动会从类的根路径下开始查找资源 -->
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>- 注意:
- 这个文件名不是必须叫做
mybatis-config.xml
,可以用其他名字,只是大家都采用这个名字。 - 这个文件存放的位置也不是固定的,可以随意,但一般情况下,会放到类的根路径下(我们放在
resources
目录下)。
- 这个文件名不是必须叫做
- 注意:
编写
XxxMapper.xml
文件,在这个配置文件中编写 sql 语句。1
2
3
4
5
6
7
8
<mapper namespace="car">
<!-- insert语句, id是这条sql语句的唯一标识,这个id就代表了这条sql语句-->
<insert id="insertCar">INSERT INTO t_car(id, car_num, brand, guide_price, produce_time, car_type) VALUES (null, '1003', '问界', 35.00, '2023-10-10', '新能源')</insert>
</mapper>- 这个文件名也不是固定的,放的位置也不是固定的,在这里我们给它起名为
CarMapper.xml
,放到类的根路径下(我们放在resources
目录下)
- 这个文件名也不是固定的,放的位置也不是固定的,在这里我们给它起名为
在
mybatis-config.xml
文件中指定XxxMapper.xml
文件的路径。1
<mapper resource="CarMapper.xml"/>
- 注意:
resource
属性会自动从类的根路径下开始查找资源。
- 注意:
编写 Mybatis 程序:使用 Mybatis 的类库,编写 mybatis 程序,连接数据库,做CRUD。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package com.f.mybatis.test;
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;
/**
* @author fzy
* @date 2023/12/29 21:25
*/
public class MybatisIntroductionTest {
public static void main(String[] args) throws IOException {
// 1.获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.获取SqlSessionFactory对象
InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); // getResourceAsStream默认从类的根路径下开始查找资源
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); // 一般情况下,一个数据库对应一个SqlSessionFactory对象
// 3.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(); // 如果使用的事务管理器是JDBC的话,底层实际上会执行:conn.setAutoCommit(false);
// 4.执行sql语句
int insertCar = sqlSession.insert("insertCar"); // 返回值是影响数据库表当中的记录条数
System.out.println("插入了 " + insertCar + " 条记录.");
// 5.手动提交(sqlSession默认不会自动提交)
sqlSession.commit(); // 如果使用的事务管理器是JDBC的话,底层实际上还是会执行conn.commit();
}
}在Mybatis中,负责执行sql语句的对象叫做:
SqlSession
SqlSession
是专门用来执行 sql 语句的,是 Java 程序和数据库之间的一次会话。要想获取
SqlSession
对象,需要先获取SqlSessionFactory
对象,通过SqlSessionFactory
对象来生产SqlSession
对象。- 怎么获取
SqlSessionFactory
对象?- 首先获取
SqlSessionFactoryBuilder
对象 - 再通过
SqlSessionFactoryBuilder
对象的build
方法,来获取一个SqlSessionFactory
对象。
- 首先获取
- 怎么获取
因此,Mybatis 核心对象包括:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
获取
SqlSession
对象的流程为:SqlSessionFactoryBuilder
–创建–>SqlSessionFactory
–生产–>SqlSession
。
总结:编写 Mybatis 程序要涉及以下内容:
- 两种
xml
文件:mybatis-config.xml
,这是核心配置文件,主要配置连接数据库的信息等。SqlSessionFactory
对象的创建需要这个文件。XxxMapper.xml
,这个文件是专门用来编写 sql 语句的配置文件(一个表对应一个)。
- 三个 Mybatis 核心对象:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
- 两种
★注意细节
resource
目录:- 放在这个目录当中的,一般都是资源文件、配置文件。
- 直接放到
resources
目录下的资源,等同于放到了类的根路径下。
Resources.getResourceAsStream
:小技巧:以后凡是遇到 resource 这个单词,大部分情况下,这种加载资源的方式就是从类的根路径下开始加载(开始查找)。
优点:采用这种方式,从类路径当中加载资源,项目的移植性很强。项目从 windows 移植到 linux,代码不需要修改,因为这个资源文件一直都在类路径当中。
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
底层的源代码其实就是:1
2
3
4
5
6
7
8
9
- `ClassLoader.getSystemClassLoader()` 获取系统的类加载器。
系统类加载器有一个方法叫做:`getResourceAsStream`,它就是从类路径当中加载资源的。
- 通过源代码分析发现:
```java
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");1
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
mybatis 中有两个主要的配置文件:
- 一个是
mybatis-config.xml
,这是核心配置文件,主要配置连接数据库的信息等。(一个) - 另一个是
XxxMapper.xml
,这个文件是专门用来编写 sql 语句的配置文件。(一个表对应一个)t_user
表,一般会对应一个UserMapper.xml
。t_student
表,一般会对应一个StudentMapper.xml
。
- 一个是
mybatis 核心配置文件的名字,不一定是:
mybatis-config.xml
,可以是其它名字。mybatis 核心配置文件存放的路径,也不一定是在类的根路径下。可以放到其它位置。但为了项目的移植性,健壮性,最好将这个配置文件放到类路径下面。
CarMapper.xml
文件的名字是固定的吗?CarMapper.xml
文件的路径是固定的吗?- 都不是固定的。
<mapper resource="CarMapper.xml"/>
中的resource
属性:这种方式是从类路径当中加载资源。<mapper url="file:///d:/CarMapper.xml"/>
中的url
属性:这种方式是从绝对路径当中加载资源。mybatis 配置文件
XxxMapper.xml
中的 sql 语句结尾的;
可以省略。
2.2 Mybatis事务管理机制
关于 mybatis 的事务管理机制。
在
mybatis-config.xml
文件中,可以通过以下的配置进行 mybatis 的事务管理1
<transactionManager type="JDBC"/>
type
属性的值包括两个:JDBC(jdbc)
、MANAGED(managed)
。type
后面的值,只有以上两个值可选,不区分大小写。
在 mybatis 中提供了两种事务管理机制:
JDBC
事务管理器:mybatis 框架自己管理事务,自己采用原生的 JDBC 代码去管理事务:
1
2
3conn.setAutoCommit(false); 开启事务。
...业务处理...
conn.commit(); 手动提交事务使用 JDBC 事务管理器的话,底层创建的事务管理器对象:
JdbcTransaction
对象。如果你编写的代码是下面的代码:
1
2
3
4SqlSession sqlSession = sqlSessionFactory.openSession(true); // 传入了参数true
表示没有开启事务。因为这种方式不会执行:conn.setAutoCommit(false);
在JDBC事务中,没有执行conn.setAutoCommit(false);那么autoCommit就是true。
如果autoCommit是true,就表示没有开启事务。只要执行任意一条DML语句就自动提交一次。
MANAGED
事务管理器:这种机制下,mybatis 不再负责事务的管理了。事务管理交给其它容器来负责。例如:spring。
对于我们当前的单纯的只有 mybatis 的情况下,如果配置为:MANAGED,那么事务这块是没人管的。没有人管理事务表示事务压根没有开启。
没有人管理事务就是没有事务。
2.3 一个完整的Mybatis程序
在 Mybatis 入门程序的基础上,加上
try-catch-finally
语句块,并加上事务处理机制,形成一个比较完整的 Mybatis 程序。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40package com.f.mybatis.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* @author fzy
* @date 2023/12/30 11:28
*/
public class MybatisCompleteTest {
public static void main(String[] args) {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = null;
SqlSessionFactory sqlSessionFactory = null;
SqlSession sqlSession = null;
try {
sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 开启会话(底层会开启事务)
sqlSession = sqlSessionFactory.openSession();
// 执行 sql 语句,处理相关业务
int count = sqlSession.insert("insertCar");
System.out.println("插入 " + count + " 条数据");
// 如果没有发生任何异常,则提交事务
sqlSession.commit();
} catch (Exception e) {
// 回滚事务
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 关闭会话,释放资源
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
2.4 JUnit单元测试
JUnit 是专门做单元测试的组件。
在实际开发中,单元测试一般是由我们 Java 程序员来完成的。
我们要对我们自己写的每一个业务方法负责任,要保证每个业务方法在进行测试的时候都能通过。
测试的过程中涉及到两个概念:
- 期望值 expected
- 实际值 actual
期望值和实际值相同表示测试通过,期望值和实际值不同则单元测试执行时会报错。
使用 Junit 的步骤:
引入依赖:
1
2
3
4
5
6
7<!-- junit依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>编写单元测试类【测试用例】,测试用例中每一个测试方法上使用
@Test
注解进行标注。测试用例的名字以及每个测试方法的定义都是有规范的:
- 测试用例的名字:
你要测试的类名 + Test
,XxxTest
- 测试方法声明格式:
public void test业务方法名(){}
例如:
1
2
3
4
5
6
7
8
9
10
11// 测试用例
public class CarMapperTest{
// 测试方法
public void testInsert(){}
public void testUpdate(){}
}- 测试用例的名字:
在类上执行,或者在方法上执行测试。
- 在类上执行时,该类中所有的测试方法都会执行。
- 在方法上执行时,只执行当前的测试方法。
在Mybatis中引入Junit
1 | package com.f.mybatis.test; |
2.5 Mybatis集成日志框架logback
引入日志框架的目的是为了看清楚 mybatis 执行的具体 sql。
启用标准日志组件,只需要在
mybatis-config.xml
文件中添加以下配置:1
2
3<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>STDOUT_LOGGING
是标准日志,mybatis 框架本身己经实现了这种标准日志。
启用
logback
日志组件,可以在mybatis-config.xml
文件中添加以下配置:1
2
3<settings>
<setting name="logImpl" value="SLF4J" />
</settings>- logback 日志框架实现了 SLF4J 标准。
- 不添加这个配置
<setting name="logImpl" value="SLF4J" />
也行。因为未指定时将自动查找。
标准日志也可以用,但是配置不够灵活,可以集成其他的日志组件,例如:
log4j
,logback
等。logback
是目前日志框架中性能较好的,较流行的,所以我们选它。
使用
logback
步骤:在
pom.xml
文件中引入 logback 相关依赖:1
2
3
4
5
6
7<!-- logback依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.12</version>
<scope>test</scope>
</dependency>引入 logback 相关配置文件(文件名只能叫做
logback.xml
或logback-test.xml
,必须放到类路径当中)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<!--<appender-ref ref="FILE"/>-->
</root>
</configuration>再次执行单元测试方法
testInsertCar
,查看控制台是否有 sql 语句输出:1
2
3
4......
2023-12-30 12:53:40.336 [main] DEBUG car.insertCar - ==> Preparing: INSERT INTO t_car(id, car_num, brand, guide_price, produce_time, car_type) VALUES (null, '1003', '问界', 35.00, '2023-10-10', '新能源')
2023-12-30 12:53:40.364 [main] DEBUG car.insertCar - ==> Parameters:
......