附加:(补):MySQL、JDBC、Apache Commons DbUtils,Mybatis、Spring JDBC:【数据库连接,DataSource数据源,事务控制】的总结和梳理;

说明:

(1)为什么写了本篇博客:在【SSM开发慕课书评网6:项目准备与SSM整合四:整合【logback日志】,【声明式事务】 ,【JUnit单元测试】;】中,SSM项目整合【声明式事务】时,发现以前接触的MySQL、JDBC、Mybatis、Spring JDBC中的【获取数据库连接、DataSource数据源、事务控制 】等内容,比较庞杂和容易混乱,所以想梳理一下;

(2)本篇博客尚未彻底解决的问题:

     ● Mybatis在查询时的事务控制,还没有彻底搞清楚;(最好的方式去看下Mybatis的手册,去寻求解释)

     ● 本篇博客介绍的Mybatis和Spring都是分开介绍的,至于在SSM整合的项目中,如何设置数据源,如何访问数据库,其变化还是比较大的;这些内容,将会在【 (17)SSM开发慕课书评网】也就是本专栏中给予展现;

(3)本篇博客的内容,在前面的几个专栏中都有介绍;本篇博客只是一个梳理和总结;

目录

1.MySQL本身;

2. 最初的JDBC;

3.Apache Commons DbUtils;

中间Summary;

4.1Mybatis框架;

4.2Mybatis框架,在单纯Mybatis项目中的使用; (这儿的内容,已经比较接近实际开发的状况了)

5.Spring JDBC;

Summary:上面介绍Mybatis和Spring都是分开介绍的,在SSM整合的项目中,其变化还是比较大的。


  说明:这儿的理解可能存在错误或偏差,随时修改。

1.MySQL本身;

(1)MySQL作为一款成熟和商用的数据库,我们在【(7)MySQL基础】专栏中对其进行了系统性介绍,如有需要可以随时去快速参考;

(2)这儿是直接通过SQL语言和MySQL打交道;比如我们可以在Navicat这个图形化工具中,直接使用SQL语言来和MySQL打交道;

(3)MySQL默认情况下,执行一条SQL语句之前都会为我们开启事务,等这条SQL语句执行完毕之后,MySQL会自动提交事务;

(4)但是,对于某些复杂的业务,尤其是哪些【复杂的,要么全做,要么一个也不做】的业务;我们就需要去手动控制事务了;

(5)为了能手动控制事务:在SQL中,可以通过【START TRANSACTION】开启手动控制事务,然后在后面写SQL语句就行了,然后可以通过【COMMIT 或 ROLLBACK】来提交或回滚事务;(自然,【START TRANSACTION】和【COMMIT 或 ROLLBACK】之间的SQL语句,都属于同一个事务)

2. 最初的JDBC;

(0)本部分的内容在【(9)JDBC入门】专栏中均有系统和详细的介绍,如有需要可以随时去快速参考;

(1)Java为了能够访问各种数据库,Java工程师提出了JDBC这个统一的接口和标准;然后,MySQL就提供了相应的MySQL驱动程序;这样以后,Java程序既可以通过JDBC,借助MySQL的驱动程序去访问MySQL数据库了;

(2)最初的情况:最开始的时候,如果我们不封装工具类,不使用Druid等连接池,而且没有主动关心事务控制时,那么我们在需要访问数据库的地方去加载JDBC驱动、创建数据库连接,然后才能去访问数据库;自然,此时在访问数据库的时候,不涉及主动进行事务控制的内容;

(3)创建了DbUtils工具类:后来为了方便,我们封装了一个DbUtils工具类,但仍然没有使用Druid等连接池,而且没有主动关心事务控制时;其实这儿和(2)没什么区别,只是封装一个工具类、更方便了而已;

     ● 这儿的DbUtils类,只有【获取Connection的方法】和【关闭Connection、ResultSet、Statement的方法】;其中不涉及主动进行事务控制的内容;

package com.imooc.jdbc.common;

import java.sql.*;

public class DbUtils {

    /**
     * 创建数据库连接
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public static Connection getConnection() throws SQLException, ClassNotFoundException {
        //加载并注册JDBC驱动,和,创建数据库连接会产生异常;
        // 这儿将异常抛出,而不是捕获;在实际调用这个getConnection()方法的时候,再对这个异常捕获
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUincode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true", "root", "12345");
        return conn;
    }

    /**
     * 关闭数据库连接
     * 注:因为关闭方法中,在关闭前都做了判断是不是null,所以当实参是null的时候也是没问题的。即比如新增、删除、更新操作没有ResultSet,因为这儿ResultSet形参可以为null;所以,插叙,新增,删除,更新都可以调用这个方法;
     * @param rs:结果集对象;
     * @param stmt:执行SQL的Statement对象;这儿的形参是Statement类型,因为PrepareStatement是Statement的子接口,所以当实参是PrepareStatement类型的时候也没问题。
     * @param conn:连接对象;
     */
    public  static void closeConnection(ResultSet rs, Statement stmt,Connection conn){
        try {
            if (rs != null) {  // 如果rs != null,代表rs被实例化了,所以这儿需要关闭一下,进行释放;
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) {  // 如果rs != null,代表stmt被实例化了,所以这儿需要关闭一下,进行释放;
                stmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null && conn.isClosed() == false) {  // conn.isClosed()==false代表这个连接还没有关闭,还正在使用中;
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

     ● 然后,我们在需要访问数据库的地方,直接通过DbUtils工具类去实现【获取Connection连接】和【关闭Connection、ResultSet、Statement】的功能;自然,此时在访问数据库的时候,其中同样不涉及主动进行事务控制的内容;

(4)引入了手动事务控制:但是,有点时候(增删改),手动控制事务是必需的;此时的案例还是使用(3)中介绍的DbUtils工具类,但仍然没有使用Druid等连接池,但是我们主动关心了事务控制;

可以看到,我们通过【Connection.setAutoCommit(false); 关闭自动提交,实现手动事务控制】;然后,通过【Connection.commit(),Connection.rollback()】来提交或回滚事务;

(5)引入了Druid等连接池:后来,为了提高程序执行效率,我们引入了数据库连接池(Druid,C3P0等);此时的案例使用(3)中介绍的DbUtils工具类(只利用了其中的【关闭Connection、ResultSet、Statement】的功能);但是这儿,出于【专注于介绍连接池,防止知识过多而迷糊】的目的,我们并没有主动关心事务控制;

     ● Druid数据库连接池:首先需要引入Druid的依赖;

然后,编写Druid的配置文件;

然后,就可以在代码中使用了,如DruidSample类:(1)加载属性文件;(2)获取DataSource数据源对象;(3)创建数据库连接。

package com.imooc.jdbc.sample;
 
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.imooc.jdbc.common.DbUtils;
 
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
 
/**
 * Druid连接池配置与使用
 */
public class DruidSample {
    public static void main(String[] args) {
        //1.加载属性文件
        Properties properties = new Properties();
        //以前接触过,DruidSample.class.getResource(“某个文件”)获取当前类路径下对应文件的路径;
        String propertiesFile = DruidSample.class.getResource("/druid-config.properties").getPath();
        System.out.println("***"+propertiesFile+"***");
        try {
            // 容纳错考虑:提取的配置文件路径:base64编码转成utf-8编码;(以前遇到过)
            propertiesFile = new URLDecoder().decode(propertiesFile,"UTF-8");
            properties.load(new FileInputStream(propertiesFile));
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //2.获取DataSource数据源对象
        // DataSource数据源对象:java.sql提供的一个接口;利用DataSource指代我们要操作的数据库是什么;
        // DataSource也提供了获取数据库连接的方法;;;所谓数据源就是数据库在JDBC中的别称;
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            //通过DruidDataSourceFactory工厂类,创建数据源;
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            //3.创建数据库连接
            conn = dataSource.getConnection();
            pstmt = conn.prepareStatement("select * from employee limit 0,10");
            rs = pstmt.executeQuery();
            while (rs.next()) {
                Integer eno = rs.getInt(1);
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            /**
             * 不使用连接池:conn.close()关闭连接;
             * 使用连接池:conn.close()将连接回收至连接池;
             */
            DbUtils.closeConnection(rs,pstmt,conn);
        }
 
    }
}

     ● C3P0数据库连接池:首先需要引入C3P0的依赖;

然后,编写C3P0的配置文件;

然后,就可以在代码中使用了,如C3P0Sample类:(1)加载属性文件;(2)获取DataSource数据源对象;(3)创建数据库连接。

package com.imooc.jdbc.sample;
 
import com.imooc.jdbc.common.DbUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
public class C3P0Sample {
    public static void main(String[] args) {
        //1.加载配置文件
        //2.创建DateSource
        // 因为C3P0配置文件的名字是定死的,必须是c3p0-config.xml,而且必须是放在src的根路径下(自然工程编译后,这个配置文件会到classes的根路径下),
        // 这样在执行new ComboPooledDataSource();的时候就会自动加载这个配置文件;并且根据这个配置文件创建DataSource数据源对象;
        DataSource dataSource = new ComboPooledDataSource();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            //3.得到数据库连接
            conn = dataSource.getConnection();
            pstmt = conn.prepareStatement("select * from employee limit 0,10");
            rs = pstmt.executeQuery();
            while (rs.next()) {
                Integer eno = rs.getInt(1);
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            /**
             * 不使用连接池:conn.close()关闭连接;
             * 使用连接池:conn.close()将连接回收至连接池;
             */
            DbUtils.closeConnection(rs,pstmt,conn);
        }
    }
}

3.Apache Commons DbUtils;

(0)在【JDBC入门十六:Apache Commons DBUtils;(简化:增删改查)】介绍了Apache Commons DbUtils;

(1)Commons DbUtils是Apache这个机构开发的,其对JDBC进行了简单封装,目的是简化JDBC的编码工作量;

(2)这儿介绍Commons DbUtils时,使用了Druid连接池,没有使用像前面定义的那种DbUtils(可以理解,这儿专注于介绍Commons DbUtils,没有使用DbUtils可能仅仅是防止知识太多而迷糊),然后在增删改时开启了手动事务控制;

(3)首先,引入Commons DbUtils依赖;然后,就可以愉快的在代码中使用Commons DbUtils来简化JDBC了;

     ● 查询时:如下面的案例代码:

package com.imooc.jdbc.sample;
 
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.imooc.jdbc.hrapp.entity.Employee;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
 
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Properties;
 
/**
 * Apache Commons DBUtils + Druid联合使用演示
 */
public class DBUtilsSample {
    private static void query(){
        Properties properties = new Properties();
        String propertiesFile = DBUtilsSample.class.getResource("/druid-config.properties").getPath();
        try {
            propertiesFile = new URLDecoder().decode(propertiesFile, "UTF-8");
            properties.load(new FileInputStream(propertiesFile));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            // 下面就演示如何使用Commons DBUtils快速完成数据的参数化查询了
            //QueryRunner翻译过来就是“查询执行者”
            QueryRunner qr = new QueryRunner(dataSource);//QueryRunner就知道向哪一个数据库来进行读取或者写入了;
            //BeanListHandler<>():帮助我们自动的将结果转换为对应的实体类;
            //下面这句话的意思是:执行第一个参数的SQL语句,将执行结果包装成一个List对象,这个List中每一个记录都是一个Employee实体类对象;
            // 这个实体类属性必须要和数据表中的字段名称完全相同!!!(这个条件有点严格。)
            // 第三个参数new Object[]{10}是给第一个参数中的?赋值的;
            List<Employee> list = qr.query("select * from employee limit ?,10", new BeanListHandler<>(Employee.class), new Object[]{10});
            for (Employee emp : list) {
                System.out.println(emp.getEname());
            }
            //在上面的过程中,并没有任何涉及到任何连接(Connection)的操作。在执行qr.query()时,Commons DBUtils会创建一个连接,当把这
            // 个查询方法qr.query()执行完毕后,连接就会自动的被关闭,并不需要我们手动的介入。。。
            // 所以,我们不需要手动关闭连接的那些东西。
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    public static void main(String[] args) {
        query();
    }
}

     ● 增删改时:如下面的案例代码:

package com.imooc.jdbc.sample;
 
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.imooc.jdbc.hrapp.entity.Employee;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
 
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
 
/**
 * Apache Commons DBUtils + Druid联合使用演示
 */
public class DBUtilsSample {
 
 
    /**
     * 更新操作
     */
    public  static void update(){
        Properties properties = new Properties();
        String propertiesFile = DBUtilsSample.class.getResource("/druid-config.properties").getPath();
        Connection conn = null;
        try {
            propertiesFile = new URLDecoder().decode(propertiesFile, "UTF-8");
            properties.load(new FileInputStream(propertiesFile));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            // 写操作离不开事务,而事务又是基于连接的,所以这儿不许先获取连接
            conn = dataSource.getConnection();
            conn.setAutoCommit(false);//将自动提交关闭。这样以后,才能手动管理事务
            String sql1 = "update employee set salary=salary+1000 where eno=?";
            String sql2 = "update employee set salary=salary-500 where eno=?";
            QueryRunner qr = new QueryRunner();// 在数据写入的时候,是不需要DataSource数据源对象的;
            //update()方法可以用于,新增、更新、删除;
            qr.update(conn, sql1,new Object[]{1000});
            qr.update(conn, sql2, new Object[]{1001});
            conn.commit();
        }catch (Exception e) {
            e.printStackTrace();
            try {
                if (conn != null && !conn.isClosed() ){
                    conn.rollback();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
 
        }finally {
            try {
                if (conn != null && !conn.isClosed()) {
                    conn.close();//对数据库连接进行回收
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
 
 
    public static void main(String[] args) {
        update();
    }
}

(4)其实,这样看来,【Apache Commons DbUtils】虽然简化了JDBC的开发,但简化力度有限;

中间Summary;

(1)只要上面的内容自己认真看了,理解了;就能够感受到,像【Druid等连接池】,【DbUtils工具类】【手动事务控制】,【Apache Commons DbUtils】等内容是可以任意组合使用的;

4.1Mybatis框架;

(0)本部分的内容在【(11)Mybatis】专栏中均有系统和详细的介绍,如有需要可以随时去快速参考;

(1)Mybatis作为一款优秀的持久层框架,其底层基础是JDBC,在JDBC的基础上进行了扩展和封装;这个框架可以帮助我们更高效的操作数据库;

(2)引入Mybatis依赖:首先,为了能在项目中使用Mybatis,需要引入【mybatis依赖】和【jdbc的MySQL驱动程序的依赖】;

(3)创建Mybatis配置文件,配置数据源:然后,就是编写Mybatis的配置文件,目的是配置DataSource数据源,而且一开始我们使用的是Mybatis提供的连接池;

(4)创建一个MyBatisUtils工具类:为了提高效率,这儿一开始就封装一个MyBatisUtils工具类;这个工具类,仅提供了获取sqlSession和关闭sqlSession的方法;其中没有主动关心事务控制的内容;

package com.imooc.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;
import sun.misc.ExtensionInstallationException;
 
import java.io.IOException;
import java.io.Reader;
 
/**
 * MyBatis工具类
 * (1)创建全局唯一的SqlSessionFactory对象;(2)获取SqlSession的方法;(3)关闭SqlSession的方法;
 */
public class MyBatisUtils {
    //sqlSessionFactory对象设置成静态的,这个对象属于类的;
    private static SqlSessionFactory sqlSessionFactory = null;
    static{
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config1.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            // 如果出现了异常,除了上面打印异常,还需要将这个异常向上抛,让使用这个类的程序也知道这儿报错了;
            // 这儿主动抛了ExceptionInInitializerError,即在类的初始化过程中产生了错误;即调用者捕获了这个异常,就能够明白,
            // mybatis在初始化的时候产生了错误,
            throw new ExceptionInInitializerError(e);
        }
    }
 
    /**
     * 获得SqlSession对象的方法;;;;
     * 在其他地方调用这个方法获得SqlSession对象后,后续就可以利用SqlSession完成数据表的增删改查了;
     * 说明:工具类中的方法,一般使用static进行描述,这样以后通过类名就能直接调用了;
     * @return
     */
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }
 
    /**
     * 关闭SqlSession的方法;
     * @param sqlSession
     */
    public static void closeSession(SqlSession sqlSession){
        if (sqlSession != null){
            sqlSession.close();
        }
    }
}

(5)Mybatis查询:然后,就是基于(4)中的MyBatisUtils工具类,进行查询了,在查询的过程中,我们并没有主动关心事务控制;

(6)Mybatis增删改:然后,就是基于(4)中的MyBatisUtils工具类,进行增删改了,在增删改的时候,我们就需要去主动关心事务控制了;

(7)一个疑问:Mybatis查询时的事务控制?:(这个疑问未彻底解决)可以看到,我们并没有写像前面的【conn.setAutoCommit(false);】这种类似的语句来开启手动管理事务;而且,在(5)查询时,我么没有session.commit()或session.rollback()对事物进行提交或回滚;但是,在(6)增删改时,我们就有session.commit()或session.rollback()对事物进行提交或回滚了。这是为什么?

目前的一个可以勉强糊弄自己的解释:为什么 CUD 过程中必须使用 sqlSession.commit()提交事务?主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,来关闭自动事务控制,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。这句话参考自【Mybatis 的事务控制】;

同时,似乎可以参考【MySQL中的查询事务问题 - battor - 博客园】这篇博客还没看;

(8)然后,在Mybatis中引入了C3P0连接池:引入C3P0依赖,创建数据源工厂类,在Mybatis配置文件中配置数据源,使用;

我们更改了DataSource数据源,由【Mybatis自己的连接池】改为了【C3P0连接池】;

4.2Mybatis框架,在单纯Mybatis项目中的使用; (这儿的内容,已经比较接近实际开发的状况了)

(0)本部分的内容在【(12)慕课OA系统(Mybatis项目案例,比较重要!)】专栏中均有系统和详细的介绍,如有需要可以随时去快速参考;

(1)引入依赖:引入【mybatis依赖】,【jdbc的MySQL驱动程序的依赖】,【Druid连接池依赖】;即,这儿我们使用了阿里的Druid连接池;

(2)创建Druid连接池的数据源工厂类:创建Druid和Mybatis兼容所需的数据源工厂类:DruidDataSourceFactory类;

(3)编写Mybatis配置文件,配置DataSource数据源:编写Mybatis的配置文件mybatis-config.xml,配置DataSource数据源;

<?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>
    <!--开启驼峰命名转换-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
 
    <environments default="dev">
        <!--开发环境配置-->
        <environment id="dev">
            <!--事务管理器采用JDBC方式-->
            <transactionManager type="JDBC"></transactionManager>
            <!---->
            <dataSource type="com.imooc.oa.datasource.DruidDataSourceFactory">
                <!--以下几项,就是JDBC连接属性了-->
                <!--设置MySQL驱动类;因为我们使用的MySQL驱动是8版本,所以这儿的value需要加上"cj"-->
                <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
                <!--设置url数据库连接字符串。。。其中【characterEncoding=UTF-8】(采用UTF-8编码进行数据传输)
                和【serverTimezone=Asia/Shanghai】(设置当前服务器的时区,这样才数据库中存储的时间才是正确的。)-->
                <property name="url" value="jdbc:mysql://localhost:3306/imooc-oa ? useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="12345"/>
                <!--连接池初始连接数-->
                <property name="initialSize" value="10"/>
                <!--连接池最大连接数-->
                <property name="maxActive" value="20"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/test.xml"/>
    </mappers>
</configuration>

可以看到我们在配置文件中配置了以下几项内容:【采用JDBC的commit和rollback来进行事务的提交和回滚】,【使用Druid连接池的数据源】,【数据库连接字符串】,【数据库用户名和密码】,【连接池的几项配置项】等;

(4)创建MyBatisUtils工具类:这个工具类和前面的DbUtils类相比,有了很大的改善。这个工具类直接提供了查询和增删改的方法(背后有函数式编程和Lambda表达式的支撑),我们直接调用方法就能完成对应的功能,也不用关心手动sqlSession的问题;同时在该工具类中设置了事务的提交和回滚;

package com.imooc.oa.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;
 
import java.io.Reader;
import java.util.function.Function;
 
public class MybatisUtils {
    //利用static(静态)属于类不属于对象,且全局唯一
    private static SqlSessionFactory sqlSessionFactory = null;
    //利用静态块在初始化类时实例化sqlSessionFactory
    static{
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            //初始化错误时,通过抛出异常ExceptionInInitializerError通知调用者
            //将产生的异常抛出去
            throw new ExceptionInInitializerError(e);
        }
    }
 
    /**
     * 执行SELECT查询SQL
     * @param func:要执行查询语句的代码块
     * @return:查询结果
     */
    public static Object executeQuery(Function<SqlSession,Object> func){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            Object obj = func.apply(sqlSession);
            return obj;
        }finally {  // catch块可以不写
            // 为了保证sqlSession一定会被关闭,将其写在finally中;此时,即使try中报错了,finally中的代码也一定会执行;
            sqlSession.close();
        }
    }
 
    /**
     * 执行INSERT/UPDATE/DELETE写操作SQL
     * @param func:要执行的写操作代码块
     * @return:写操作后返回的结果
     */
    public static Object executeUpdate(Function<SqlSession,Object> func){
        SqlSession sqlSession = sqlSessionFactory.openSession(false);
        try {
            Object obj = func.apply(sqlSession);
            sqlSession.commit();
            return obj;
        }catch (RuntimeException e){  // 因为这儿,在程序运行过程中才会产生各种各样的异常,所以这儿只需要捕捉RuntimeException就可以了;
            sqlSession.rollback();
            throw e;// 捕获了这个异常后,需要将这个异常抛出去;
        }finally {  // catch块可以不写
            // 为了保证sqlSession一定会被关闭,将其写在finally中;此时,即使try中报错了,finally中的代码也一定会执行;
            sqlSession.close();
        }
    }
 
}

上面遇到的【(7)一个疑问:Mybatis查询时的事务控制?:(这个疑问未彻底解决)】 这儿依旧体现出来了;这个问题还没有彻底搞清楚啦;

(5)正式开发:然后,就可以愉快的使用Mybatis就行访问数据库了;(这儿仅展示了广泛使用的Mybatis接口开发方式);

上图没必要再啰嗦阐述:只需要看到两点【我们直接调用MyBatisUtils类的查询或增删改的方法,我们不用关心“sqlSession的获取、关闭”和“事务控制”,这些工作MyBatisUtils类已经帮我们做了】【Mybatis接口开发方式】;

5.Spring JDBC;

(0)本部分的内容在【(15)Spring基础:IoC;AOP;JDBC;】专栏中均有系统和详细的介绍,如有需要可以随时去快速参考;

(1)Spring JDBC是Spring机构提供的,其是对JDBC的封装;和【Mybatis】相比,【Spring JDBC】的执行效率更高;

(2)首先,引入依赖:引入【spring-jdbc依赖】,【jdbc的MySQL驱动程序的依赖】;

(3.1)配置数据源:在Spring的ApplicationContext.xml配置文件中,配置DataSource数据源:可以看到,此时我们使用的是Spring-jdbc数据源,没有使用Druid等连接池;(因为这儿我们是基于Spring框架,所以这些关键的对象我们都配置在了IoC容器中)

(3.2)配置JdbcTemplate对象:Spring JDBC通过【JdbcTemplate对象】去实现增删改查的,所以需要在applicationContext.xml中配置一下JdbcTemplate对象;(因为这儿我们是基于Spring框架,所以这些关键的对象我们都配置在了IoC容器中)

能够看到,像前面的那种DbUtils工具类或MyBatisUtils工具类;在Spring JDBC中不需要。

(4)查询:这儿还没有涉及主动的事务控制;

(5)增删改:这儿(出于专注于介绍JdbcTemplate对象的目的)还没有涉及主动的事务控制;

(6)引入了事务控制:编程式事务:但是,为了能够实用,Spring JDBC必须要引入事务控制;(Spring JDBC是封装的JDBC,JDBC有事务控制,Spring JDBC也自然会有事务控制啦)

     ● 首先,在ApplicationContext.xml配置文件中,配置【DataSourceTransactionManager】事务管理器对象;

     ● 然后,在需要事务控制的地方去使用【DataSourceTransactionManager】即可;

     ● 虽然,这种方式也不简洁,但也要知道Spring JDBC对JDBC进行了封装,Spring JDBC自然也做了一些支撑工作;

(7)引入了事务控制:声明式事务:然而,编程式事务还是比较麻烦的,因此基于AOP提出了声明式事务;

     ● 因为声明式事务基于AOP,所以需要先引入【aspectjweaver】依赖;

     ● 和编程式事务一样,声明式事务也需要在applicationContext.xml中配置【DataSourceTransactionManager】事务管理器对象;

     ● 在applicationContext.xml中:事务通知配置:决定哪些方法使用事务,哪些方法不使用事务;

     ● 配置好了之后,我们在实际编写代码的时,对于那些需要手动控制事务的地方,只要我们配置了声明式事务,我们就不需要在进行手动事务控制了,因为声明式事务都已经帮我们做了;

(8)说明一下:在介绍【Spring JDBC】时,没有使用Druid等连接池,使用的都是【springframework.jdbc.datasource.】即Spring JDBC自己的DataSource数据源;


Summary:上面介绍Mybatis和Spring都是分开介绍的,在SSM整合的项目中,其变化还是比较大的。

(1)至于在SSM整合的项目中,如何设置数据源,如何访问数据库,其变化还是比较大的;这些内容,将会在【 (17)SSM开发慕课书评网】展现;

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值