一、基本流程
1、 使用Navicat创建MySQL数据库(powernode)的一张表(t_car);
并插入两条数据
2、 在IDEA中创建一个空项目:;
- 第一步,配置JDK
- 第二步,配置Maven的地址和本地仓库的地址
- 第三步创建一个Maven的模块
3、 修改pom.xml文件;
- 确定打包方式:
<packaging>jar</packaging>
- 添加mysql驱动和mybatis依赖
<!--mybatis核心依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
4、 编写sql的映射文件,一张表对应一个XxxMapper类【完成对这张表操作语句的封装】;
<?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">
<!--namespace先随意写一个-->
<mapper namespace="car">
<!--insert sql:保存一个汽车信息-->
<insert id="insertCar">
insert into t_car
(id,car_num,brand,guide_price,produce_time,car_type)
values
(null,'102','丰田mirai',40.30,'2014-10-05','氢能源')
</insert>
</mapper>
5、 编写MyBatis的核心配置文件【一般都放在根目录下并命名为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>
<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/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--sql映射文件创建好之后,需要将该文件路径配置到这里-->
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>
6、 编写Java程序的Mybatis代码【用一个类完成会话的创建与业务】;
package com.powernode.mybatis;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public class MyBatisIntroductionTest {
public static void main(String[] args) {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 创建SqlSessionFactory对象
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 3. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 执行sql
int count = sqlSession.insert("insertCar"); // 这个"insertCar"必须是sql的id
System.out.println("插入几条数据:" + count);
// 5. 提交(mybatis默认采用的事务管理器是JDBC,默认是不提交的,需要手动提交。)
sqlSession.commit();
// 6. 关闭资源(只关闭是不会提交的)
sqlSession.close();
}
}
- 执行SQL语句是Java和数据库之间的一次会话,那么如何建立这个会话呢?
(1)我们要创建SqlSessionFactoryBuilder类的对象,调用其build方法
(2)build需要一个数据流作为参数,进而才能创建SqlSessionFactory的对象
//可以采用两种方式来获取数据流
InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //mybatis内置的
//第一种方法底层就是由第二种方法实现的
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatis-config.xml");
(3)利用SqlSessionFactory对象去开启一个会话,用这个SqlSession的对象调用 XxxMapper.xml 中的方法,参数为方法的id,就可以执行指定的SQL语句了。
- 执行结果刷新一下数据库就可以看到:
- 为什么第三条数据id不是 3呢?
因为id我采用了自增的方式,在我第一次写 MyBatisIntroductionTest.java 时,没有手动提交。
即没有写sqlSession.commit()
,运行了两次,所以就出现了断码的现象
- 难道不可以自动提交吗?
是可以的,此处我选择的事务管理是 JDBC,JDBC事务默认是不提交的,需要手动提交。
7、 入门程序完成代码【上述代码如果在会话出现异常以后不能回滚】;
package com.powernode.mybatis;
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;
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();
}
}
}
}
二、事务管理
1、JDBC事务管理器:
- MyBatis框架自己管理事务,采用原生的JDBC代码去管理事务
conn.setAutoCommit(false); //开启事务
... 业务处理 ...
conn.commit(); //手动提交事务
- 使用JDBC事务管理器的话,底层创建的事务管理器对象:JdbcTranscation对象
- 在我们调用sqlSessionFactory.openSession()方法是内部参数默认为false,如果传入了true,那么就不会开启事务
2、MANAGED 事务管理器
- 由其他容器负责处理事务,例如:Spring
- 因为此时我们的项目中只有MyBatis,如果将事务管理设置为MANAGED就代表没有人来处理事务。
<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/powernode"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</dataSource>
</environment>
</environments>
三、单元测试
- 我们可使用 junit 来进行测试,它是专门做单元测试的一个组件
- 测试的过程中涉及两个概念:期望值、实际值【两者相同代表测试通过,否则就会产生报错】
1、 我们要将junit的依赖添加到当前项目的pom.xml文件中;
因为我们是通过Maven构建项目的,所以可以通过官网去查找依赖
<!--添加junit依赖-->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
2、 编写单元测试类,一般都叫XxxTest.java,每个方法都对应一个测试方法publicvoidtest业务方法名()
;
(1)业务类【完成加法和减法】
public class MathService {
public int sum(int num1, int num2){
return num1 + num2;
}
public int sub(int num1, int num2) {
return num1 - num2;
}
}
(2)测试类
public class MathServiceTest{
@Test
public void testSum(){
//创建对象,调用我们要测试的方法
MathService mathService = new MathService();
//实际值与预期值
int actual = mathService.sum(1,2);
int expected = 3;
//断言测试
Assert.assertEquals(expected, actual);
}
@Test
public void testSub(){
//创建对象,调用我们要测试的方法
MathService mathService = new MathService();
//实际值与预期值
int actual = mathService.sum(1,2);
int expected = -1;
//断言测试
Assert.assertEquals(expected, actual);
}
}
3、如何运行测试类?
- 在类上执行,会执行该测试类中所有的测试方法
- 在方法上执行只执行当前的测试方法
四、集成日志
- 我们通过引入日志框架来查看运行过程中的 sql 执行情况
- mybatis 提供了一种标准的日志组件,需要在 mybatis-config.xml 中添加以下配置
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
看起来不是很直观,MyBatis 也集成了其他的日志组件,例如:log4j,logback等。【此处我们以logback框架为例】
1、 引入logback的依赖;
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
2、 引入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>
3、 每次获取SqlSession对象代码很繁琐,我们可以封装一个工具类;
package com.powernode.mybatis.utils;
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 SqlSessionUtil {
private static 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);
}
}
如果要测试 CarMapper.xml 中的 Insert 方法,我们可以调用工具类简化为如下代码:
@Test
public void testInsertCar(){
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL
int count = sqlSession.insert("insertCar");
System.out.println("插入了几条记录:" + count);
sqlSession.close();
}