一、数据准备
二、开发步骤
1、引入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
</dependencies>
2、编写核心配置文件: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>
<!--
允许设置多个环境,但是每个 SqlSessionFactory 实例只能选择一种环境
设置默认的环境:development
-->
<environments default="development">
<!-- 环境配置,名称为:development -->
<environment id="development">
<!-- 配置事物管理器为 JDBC -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 配置数据库连接信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/>
<property name="username" value="root"/>
<property name="password" value="mysql"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 指定 XxxMapper.xml 文件 -->
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>
3、编写 XxxMapper.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="qiuXuan">
<!--id就代表了下面的这条sql语句-->
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null,'1003','五菱宏光',30.0,'2020-09-18','燃油车');
</insert>
</mapper>
4、在 mybatis-config.xml 文件中指定 XxxMapper.xml 文件的路径
5、编写 MyBatis 程序
-
在 MyBatis 当中 SqlSession 负责 SQL 语句的执行,是 Java 程序与数据库之间的会话
-
要获取 SqlSession 对象,需要先获取 SqlSessionFactory 对象,通过 SqlSessionFactory 工厂来生产 SqlSession 对象
如何获取 SqlSessionFactory 对象?
通过 SqlSessionFactoryBuilder 对象的 build 方法获取一个 SqlSessionFactory 对象
SqlSessionFactoryBuilder ---> SqlSessionFactory ---> SqlSession
package com.qiuxuan;
public class MyBatisIntroductionTest {
public static void main(String[] args) throws IOException {
// 获取 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
/**
* 获取 SqlSessionFactory
*
* build 方法的参数为一个 InputStream
* 指向 mybatis-config.xml 核心配置文件
*
* 可以通过 MyBatis 的 Resources 工具类获取
* 其 getResourceAsStream 方法返回的就是一个 InputStream
* 参数为核心配置文件路径(默认从类根路径[resources]查找资源)
*/
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = builder.build(is);
// 获取 SqlSession
SqlSession sqlSession = factory.openSession();
// 执行 SQL 语句(参数为 SQL 语句的 id)
int count = sqlSession.insert("insertCar");
System.out.println(count);
// mybatis 默认是不会自动提交的,需要手动提交
sqlSession.commit();
}
}
三、MyBatis 中有两个主要的配置文件
-
mybatis-config.xml(一个)
-
核心配置文件,主要配置连接数据库的信息等
-
-
XxxMapper.xml(一个表一个)
-
用于编写 SQL 语句的配置文件
-
四、Tips
mybatis 中 sql 语句的结尾 “;” 可以省略
使用 Resources.getResourceAsStream
获取资源文件的方式符合 OCP 原则,有利于程序的移植性、健壮性
若使用 FileInputStream 方式获取资源文件,当程序需要在其他系统运行时,原来的路径将会失效,需要修改 Java 代码中的资源路径,违背了 OCP 原则
也可使用类加载器获取资源:
ClassLoader.getSystemClassLoader().getResourceAsStream("资源路径");
与 Resources.getResourceAsStream
一致,都是从根路径获取资源,即 resources 目录下
ClassLoader.getSystemClassLoader()
获取的是系统类加载器,而 Resources.getResourceAsStream
底层使用的就是 ClassLoader.getSystemClassLoader()
五、MyBatis 的事务管理机制
在 mybatis-config.xml 文件中,可以通过以下的配置进行 mybatis 的事务管理
<transactionManager type="JDBC"/>
type 属性包括两个值:JDBC、 MANAGED,对应两种事务管理机制
-
JDBC 事务管理器
-
MyBatis 框架自己采用管理事务,自己采用原生的 JDBC 代码去管理事务
-
使用 JDBC 事务管理器底层创建事务管理对象的是 JdbcTransation 对象
-
conn.setAutoCommit(false);
开启事务若使用 JDBC 事务管理器,在
factory.openSession()
底层会执行此语句若使用
factory.openSession()
时传入参数 true,则底层不会执行conn.AutoCommit(false)
,也就不会开启事务,此时执行任意 DML 语句都会自动提交业务处理...
conn.commit();
提交事务
-
MANAGED 事务管理器
-
mybatis 不再负责事务的管理了,事务管理交给其他容器负责,例如:Spring
-
六、较完整的 MyBatis 程序
package com.qiuxuan;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisCompleteCodeTest {
public static void main(String[] args) {
SqlSession sqlSession = null;
try {
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象
sqlSession = sqlSessionFactory.openSession();
// 4.执行SQL
int count = sqlSession.insert("insertCar");
System.out.println("更新了几条记录:" + count);
// 5.提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 6.关闭
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
七、Junit 单元测试
JUnit 是专门做单元测试的组件。
-
在实际开发中,单元测试一般是由我们 Java 程序员来完成的。
-
要对自己写的每一个业务方法负责任,要保证每个业务方法在进行测试的时候都能通过。
-
-
测试的过程中涉及到两个概念:
-
期望值
-
实际值
-
-
期望值和实际值相同表示测试通过,期望值和实际值不同则单元测试执行时会报错。
1、引入依赖
<!-- junit依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
2、编写单元测试类【测试用例】
测试用例中每一个测试方法上使用 @Test 注解进行标注。
测试用例的名字以及每个测试方法的定义都是有规范的:
-
测试用例的名字:
XxxTest
-
测试方法声明格式:
public void test业务方法名(){}
// 测试用例
public class CarMapperTest{
// 测试方法
@Test
public void testInsert(){}
@Test
public void testUpdate(){}
}
可以在类上执行,也可以在方法上执行
-
在类上执行时,该类中所有的测试方法都会执行。
-
在方法上执行时,只执行当前的测试方法。
-
编写一个测试用例,来测试 insertCar 业务
public class CarMapperTest {
@Test
public void testInsertCar(){
SqlSession sqlSession = null;
try {
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象
sqlSession = sqlSessionFactory.openSession();
// 4.执行SQL
int count = sqlSession.insert("insertCar");
System.out.println("更新了几条记录:" + count);
// 5.提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 6.关闭
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
八、logback 日志框架
-
引入日志框架的目的是为了看清楚 mybatis 执行的具体 sql。
-
启用标准日志组件,只需要在 mybatis-config.xml 文件中添加以下配置:【可参考 mybatis 手册】
mybatis-config.xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
注意:<configuration>
里配置的位置是有顺序要求的,否则会报错
Error creating document instance. Cause: org.xml.sax.SAXParseException;
<configuration>
<properties>...</properties>
<settings>...</settings>
<typeAliases>...</typeAliases>
<typeHandlers>...</typeHandlers>
<objectFactory>...</objectFactory>
<objectWrapperFactory>...</objectWrapperFactory>
<reflectorFactory>...</reflectorFactory>
<plugins>...</plugins>
<environments>...</environments>
<databaseIdProvider>...</databaseIdProvider>
<mappers>...</mappers>
</configuration>
标准日志也可以用,但是配置不够灵活,可以集成其他的日志组件,例如:log4j,logback等。
-
logback 是目前日志框架中性能较好的,较流行的,所以选它。
-
引入 logback 相关依赖
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
-
引入 logback 相关配置文件(文件名叫做 logback.xml 或 logback-test.xml,放到类路径当中)
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<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>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MB</MaxFileSize>
</triggeringPolicy>
</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>
九、MyBatis 工具类 SqlSessionUtil 的封装
每一次获取 SqlSession 对象代码太繁琐,封装一个工具类
/**
* MyBatis工具类
*
* @author 秋玄
* @version 1.0.0
* @since 1.0.0
*/
public class SqlSessionUtil {
private static final SqlSessionFactory sqlSessionFactory;
/**
* 类加载时初始化sqlSessionFactory对象
*/
static {
try {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。
*
* @return 新的会话对象
*/
public static SqlSession openSession() {
return sqlSessionFactory.openSession(true);
}
}
一 叶 知 秋,奥 妙 玄 心