Mybatis的事务管理机制

在mybatis-config.xml文件中.可以进行mybatis的事务管理

<transactionManager type="JDBC"/>

type的值有两个

  • JDBC
  • MANAGED
JDBC事务管理器

mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务

底层创建的事务管理器对象是JdbcTransaction对象

conn.setAutoCommit(false);开启事务

进行业务处理

conn.commit():手动提交事务

SqlSession sqlSession = sqlSessionFactory.openSession();//如果使用事务管理器是JDBC的话,实际上会执行:conn.setAutoCommit(false)
sqlSession.commit();//如果使用的事务管理器是JDBC的话,实际上会执行:conn.commit()

不建议传入参数true

SqlSession sqlSession = sqlSessionFactory.openSession(true);
如果传入了参数true,那么底层就不会执行conn.setAutoCommit(false),那么autoCommit就是true
如果autoCommit是true,就表示没有开启事务,只要执行一条sql语句就提交一次
MANAGED事务管理器

mybatis不再负责事务的管理,事务管理交给其他容器来负责

当以后ssm框架进行集成的时候可以用MANAGED

但只有mybatis的框架时,如果配置managed那么这块事务是没人管的,表示事务没开启


Junit单元测试

先引入单元测试的依赖

然后在test包下创建类,起名规范就是要测试的类加Test

测试方法要加注解@Test,说明这个方法是测试方法

单元测试中有两个重要的概念

  • 实际值:被测试的业务方法的真正的执行结果
  • 期望值:执行了这个业务之后,你期望的执行结果是多少

最后加断言进行测试

Assert.assertEquals(expected,actual)
Mybatis的日志信息

Mybatis配置日志信息需要在核心配置文件中进行配置

Mybatis已经对STDOUT_LOGGING进行了实现,只需要开启即可

但STDOUT_LOGGING的日志信息不够丰富,如果想用丰富的要引入第三方组件

<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
集成logback日志框架
  1. 引入logback的依赖
  2. 引入logback所必须的xml配置文件
  • 这个配置文件的名字必须叫做logback.xml或者logback-text.xml,不能是其他的
  1. 这个配置文件必须放到根路径下,不能是其他位置
<?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">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>


    <logger name="com.apache.ibaits" level="TRACE"></logger>
    <logger name="java.sql.Connection" level="DEBUG"></logger>
    <logger name="java.sql.Statement" level="DEBUG"></logger>
    <logger name="java.sql.PreparedStatement" level="DEBUG"></logger>



    <root level="DEBUG">
        <append-ref ref="STDOUT"></append-ref>
        <append-ref ref="FILE"></append-ref>
    </root>



</configuration>

如果使用的是标准的日志需要配置settings,如果使用的第三方组件就不用配置了

Mybatis封装工具类
//一个sqlSessionFactory对应一个environment,一般一个environment对应一个数据库
//所以调用openSession的时候不用每次都创建sqlSessionFactory对象
//写在类加载器中即可

public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private MybatisUtil() {
    }

    public static SqlSession openSession() {

        return sqlSessionFactory.openSession();
    }
}
Mybatis的CRUD
  • C:Create(增)
  • R:Retrieve(查)
  • U:update(改)
  • D:delete(删)

在mybatis当中的占位符是#{}

Map集合传值

#{}传入的值是map的键

Map<String,Object> map = new HashMap<>();
        map.put("k1","1111");
        map.put("k2","比亚迪汉");
        map.put("k3",10.0);
        map.put("k4","2020-12-11");
        map.put("k5","电车");
        //第一个参数是sql语句的id
        //第二个参数是封装数据的对象
        sqlSession.insert("insertCar",map);


        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) 
        values (null,#{k1},#{k2},#{k3},#{k4},#{k5})
POJO类传值

#{}传入的值是POJO类的属性值

SqlSession sqlSession = SqlSessionUtils.openSession();
        Car car = new Car(null, "1112", "凯的拉克CT6", 55.0, "2023-12-10", "电车");
        sqlSession.insert("insertCar",car);
        sqlSession.commit();
        sqlSession.close();

insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

严格意义上来说:如果使用POJO类传值的话,#{}中实际上是mybatis调用get方法去掉get再把剩下的单词首字母小写

#{name}->#{getName}
mybatis的删除
<delete id="deleteCar">
        delete from t_car where id=#{id}
    </delete>

sqlSession.delete("deleteCar",15);
Mybatis的更新
public void testUpdateCarById(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Car car = new Car(5L,"9999","凯美瑞",30.0,"2023-12-10","燃油车");
        sqlSession.update("updateCar",car);
        sqlSession.commit();
        sqlSession.close();

    }


   <update id="updateCar">
        update t_car set
                         car_num=#{carNum},
                         brand=#{brand},
                         guide_price=#{guidePrice},
                         produce_time=#{produceTime},
                         car_type=#{carType}
        where
            id=#{id}
    </update> 
Mybatis的查询

mybatis中查询的时候mybatis底层执行了select语句之后,就一定会返回一个结果集ResultSet

需要在select标签中指定resultType来确定ResultSet封装成什么类型的Java对象

 @Test
    public void testSelectCarById(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Object o = sqlSession.selectOne("selectCar", 1);
        System.out.println(o);
        sqlSession.close();
    }
}


<select id="selectCar" resultType="POJO.Car">
        select *
        from t_car
        where id=#{id}
    </select>

查询时如果结果中的列名和封装对象中的属性名不对应那么就赋不上值

<select id="selectCar" resultType="POJO.Car">
select id,brand,car_num as carNum,guide_price as guidePrice,produce_time as produceTime,car_type as carType
from t_car
where id=#{id}
</select>
Mybatis查询所有
//resultType是封装的结果集类型,不是指定List的类型,是指定List集合中的元素类型
<select id="selectAll" resultType="POJO.Car">
select
id,car_num as carNum, brand ,guide_price as guidePrice, produce_time as produceTime,car_type as carType
from t_car
</select>


@Test
    public void testSelectAll(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        List<Object> Cars = sqlSession.selectList("selectAll");
        Cars.forEach(car-> System.out.println(car));
        sqlSession.close();
    }
Mybatis中的namespace

在sqlMapper.xml文件当中,有namespace这个属性是用来指定命名空间的,用来防止id重复

本质上mybatis的sql语句的写法是namespace.id为了防止id重复

Mybatis的核心配置文件
<?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/mybatistest"/>
                <property name="username" value="root"/>
                <property name="password" value="abc123"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="CarMapping.xml"/>
    </mappers>
</configuration>

environments是指mybatis的环境,mybatis中可以有多个环境,一个环境对应一个数据库

一个数据库对应一个SqlSessionFactory对象

default指的是默认使用的环境,指定environment的id

当创建SqlSessionFactory的时候没有指定使用哪个环境就是用默认的环境

Mybatis的事务管理器

transactionManager是事务管理器,指定mybatis具体用什么方式去管理事务

  • 第一个:JDBC:使用原生的jdbc代码来管理事务
  • 第二个:MANAGED:mybatis不再负责事务管理,将事务管理交给其他的容器来管理

在Mybatis中提供了事务管理器接口:Transaction

接口下有两个实现类:JdbcTransaction,ManagedTransaction

如果type="JdbcTransaction" 那么底层会实例化JdbcTransaction对象

如果type="ManagedTransaction" 那么底层会实例化ManagedTransaction对象

Mybatis的数据源

dataSource被称为数据源

dataSource为程序提供Connection对象,但凡是给程序员提供Connection对象的都叫数据源

数据源实际上是一套规范,JDK中有这套规范,javax.sql.DataSource(这个数据源的规范,这套接口实际上是JDK规范的)

我们自己也可以编写数据源组件,只要实现javax.sql.DataSource接口就行了,实现接口中的所有方法,这样就有了自己的数据源

数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源组件

type属性是用来指定数据源的类型,就是指定具体使用什么方法来获取Connection对象

type的属性值有三个:

  • UNPOOLED:不使用数据库连接池技术,每一次请求过来之后,都是创建新的Connection对象
  • POOLED:使用mybatis自己实现的数据库连接池
  • JNDI:集成其他第三方的数据库连接池

JNDI是一套规范,大部分web容器都实现了JNDI规范

Mybatis的properties标签

java.util.Properties类,是一个Map集合,key和value都是String类

properties是为了让核心文件的配置更灵活

<propety name="属性名" value="属性值" />
<properties resource="配置文件名" />

更多推荐