第一章 JDBC的簡介
1.1 JDBC是什么
JDBC (Java DataBase Connectivity) 是一組用于執行SQL語句的Java API,它由一組用Java語言編寫的類和接口組成,可以為多種關系型數據庫提供統一訪問。他是一種標準,是由oracle公司制定的一套使用Java語言訪問數據庫的標準.
1.2 JDBC原理圖
?
?
</center>
1.3 JDBC提供的常用接口和類
1. DriverManager: 管理數據庫驅動程序,用于建立數據庫連接
?
2. Driver: ? ? ?? 提供給各個數據庫廠商的接口,每一個數據庫廠商要想可以使用Java語言來與他們的數據庫進行通信,必須實現此接口.(主要處理與數據庫服務器之間的通信)
3. Connection: ?? 此接口具有用于聯系數據庫的所有方法
?
4. Statement: ? ? 從此接口創建的對象將SQL語句提交到數據庫
?
5. ResultSet: ? ? 在使用Statement對象執行SQL查詢后,這個對象保存從數據庫檢索的數據
?
6. SQLException: 處理數據庫應用程序中發生的異常
第二章 JDBC入門
以一個用戶表為例來使用JDBC進行增刪該查的操作
數據庫環境搭建
// 1)、創建數據庫
CREATE DATABASE jdbc DEFAULT CHARACTER SET UTF8;
// 2)、切換數據庫
USE jdbc;
// 3)、創建數據庫表
CREATE TABLE user(
?? `user_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵',
?? `user_name` VARCHAR(20) NOT NULL COMMENT '用戶名',
?? `price` double(10,2) DEFAULT 0.0 COMMENT '價格',
?? `create_time` DATETIME DEFAULT NULL COMMENT '創建時間'
)ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=UTF8 COMMENT="用戶表";
添加用戶
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","rooe","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建添加SQL語句
String sql="INSERT INTO user(user_name,price,create_time) VALUES('admin',100.12,now())";
//⑤執行sql語句,返回影響行數,如果需要獲取主鍵,要配置Statement.RETURN_GENERATED_KEYS參數
int row = statement.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
//⑥打印影響行數
System.out.println("row:"+row);
?
//如果想獲取插入用戶的主鍵可以使用statement.getGeneratedKeys()獲取
?
ResultSet resultSet=statement.getGeneratedKeys();
if(resultSet.next()){
?? int id = resultSet.getInt(1);
}
?
更新用戶
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","rooe","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建更新SQL語句
String sql="UPDATE user SET user_name='admin1',price=12.12,create_time=now() WHERE user_id=100";
//⑤執行sql語句,返回影響行數
int row = statement.executeUpdate(sql);
//⑥打印影響行數
System.out.println("row:"+row);
刪除用戶
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","rooe","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建更新SQL語句
String sql="DELETE FROM user WHERE user_id=100";
//⑤執行sql語句,返回影響行數
int row = statement.executeUpdate(sql);
//⑥打印影響行數
System.out.println("row:"+row);
查詢用戶列表
//創建一個集合對象,將從數據庫查詢出來的數據保存到集合中
List<User> users = new ArrayList<>();
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","rooe","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建SQL語句
String sql="SELECT * FROM user";
//⑤執行sql語句,返回結果集對象
ResultSet result = statement.executeQuery(sql);
while(result.next()){
? ? User user = new User();
? ? int userId = result.getInt("user_id");
? ? user.setUserId(userId);
? ? String userName = result.getString("user_name");
? ? user.setUserName(userName);
? ? double price = result.getDouble("price");
? ? user.setPrice(price);
? ? Date createTime = result.getDate("create_time");
? ? user.setCreateTime(createTime);
? ? users.add(user);
}
//打印從數據庫查詢出來的對象
System.out.println(users);
查詢一個用戶(因為JDBC沒有提供一個查詢單個對象的結果集,所以查詢單個對象時也是使用ResultSet對象,取集合中的一個對象即可)
//創建一個集合對象,將從數據庫查詢出來的數據保存到集合中
List<User> users = new ArrayList<>();
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","root","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建SQL語句
String sql="SELECT * FROM user";
//⑤執行sql語句,返回結果集對象
ResultSet result = statement.executeQuery(sql);
while(result.next()){
? ? User user = new User();
? ? int userId = result.getInt("user_id");
? ? user.setUserId(userId);
? ? String userName = result.getString("user_name");
? ? user.setUserName(userName);
? ? double price = result.getDouble("price");
? ? user.setPrice(price);
? ? Date createTime = result.getDate("create_time");
? ? user.setCreateTime(createTime);
? ? users.add(user);
}
//打印從數據庫查詢出來的對象
System.out.println(users);
查詢數據庫總記錄數
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","root","root");
//③創建Statement對象
Statement statement = conn.createStatement();
//④創建SQL語句
String sql="SELECT COUNT(*) AS count FROM user";
//⑤執行sql語句,返回結果集對象
ResultSet result = statement.executeQuery(sql);
if(result.next()){
? ? int count = result.getInt("count");
? ? System.out.println(count);
}
分頁查詢
MYSQL數據庫分頁的語法
SELECT * FROM user LIMIT [offset],[max];
MYSQL的SQL語句的語法格式帶有兩個參數分別是offset和max,而我們前端或者是客戶端給后臺發送過來的數據為pageNo(當前頁)和pageSize(每頁顯示多少條數),而SQL語句里面的max和我們前端傳送過來的pageSize是相同的都是為每頁顯示的條數。但是offset和pageNo不是相同的所以需要轉換。
轉換的公式:
offset=(pageNo-1)*pageSize
中文亂碼
url:jdbc:mysql:///jdbc?characterEncoding=utf-8&useUnicode=true
第三章 PreparedStatement接口
1. 它是擴展了Statement的接口(PreparedStatement本身也是接口)
2. 功能比Statement更強大
3. 可以動態地提供/接受參數
4. 創建PreparedStatement對象 --> conn.prepareStatement(通過Connection對象獲取)
5. 可以使用占位符(?)來進行數據綁定
6. 通過stmt.setInt(1, 35);綁定參數
添加用戶
//①加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//②創建數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbc?characterEncoding=utf-8","rooe","root");
//③準備sql,帶有(?)占位符
String sql="INSERT INTO user(user_name,price,create_time) VALUES(?,?,?)";
//④預編譯
PreparedStatement prepareStatement = conn.prepareStatement(sql);
//⑤綁定參數(參數的下標從1開始而不是像數組或者集合從0開始)
prepareStatement.setString(1, "admin");
prepareStatement.setDouble(2, 100.12);
prepareStatement.setDate(3, new Date(new java.util.Date().getTime()));
//⑥執行進行綁定參數之后的sql語句
int row = prepareStatement.executeUpdate();
System.out.println("row:"+row);
其余(刪改查)操作自己完成
第四章 JDBC的事務處理
jdbc默認情況下每執行完一條SQL就會提交到數據庫一次,因為jdbc默認提交事務的方式是自動提交,但是在正常的業務邏輯下,一個業務正常要執行多條sql語句,如果每執行完一條sql都進行事務提交就很容易出現前后數據不一致的問題,所以要保證這一組的sql語句操作都在一個事務管理中,所以我們要取消JDBC的默認事務提交
1. 使用Connection對象的setAutoCommit()方法關閉他的自動提交
2. 手動提交事務調用connection的commit()方法
3. 事務回滾調用connection的rollback()方法
第五章 JDBC批量處理
使用JDBC進行批處理的對象有兩個:
Statement?
PreparedStatement
Statement
介紹
①使用Statement對象批量添加要執行的SQL語句,事例如下:
?
? statement.addBatch(sql1);
? statement.addBatch(sql2);
? statement.addBatch(sql3);
? statement.addBatch(sql4);
②執行批處理SQL語句:statement.executeBatch();
③清除批處理命令:statement.clearBatch();
代碼
Statement statement = connection.createStatement();
//批量準備SQL
String sql1="INSERT INTO user(user_name,price,create_time) VALUES('AA',12.12,NOW())";
String sql2="INSERT INTO user(user_name,price,create_time) VALUES('BB',13.12,NOW())";
String sql3="INSERT INTO user(user_name,price,create_time) VALUES('CC',14.12,NOW())";
String sql4="DELETE FROM user WHERE user_id=100";
//批量添加SQL
statement.addBatch(sql1);
statement.addBatch(sql2);
statement.addBatch(sql3);
statement.addBatch(sql4);
//批量執行
statement.executeBatch();
PreparedStatement
代碼
String sql="INSERT INTO user(user_name,price,create_time) VALUES(?,?,?)";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
//綁定參數1
prepareStatement.setString(1, "AA");
prepareStatement.setDouble(2, 12.12);
prepareStatement.setDate(2, new Date(new java.util.Date().getTime()));
prepareStatement.addBatch();
//綁定參數2
prepareStatement.setString(1, "BB");
prepareStatement.setDouble(2, 12.12);
prepareStatement.setDate(2, new Date(new java.util.Date().getTime()));
prepareStatement.addBatch();
//執行
prepareStatement.executeBatch();
Statement和PrepareStatement的優缺點:
1.Statement可以添加不同的SQL語句INSERT UPDATE DELETE可以同時進行批處理,但是效率相對較差
?
2.PrepareStatement執行同一條SQL不同參數的SQL語句,但是效率相對較高
第六章 JDBC存儲大字段到MYSQL(了解)
6.1 大字段介紹
對于字段長度要求超過 255 個的情況下,MySQL 提供了 TEXT 和 BLOB 兩種類型。根據存儲數據的大小,它們都有不同的子類型。這些大型的數據用于存儲文本塊或圖像、聲音文件等二進制數據類型
6.2 大字段類型
4種文本: TINYTEXT(0-255字節)、TEXT(0-65535字節)、MEDIUMTEXT(0-16777215字節) 和 LONGTEXT(0-4294967295字節)
4種二進制: TINYBLOB(0-255字節)、BLOB(0-65535字節)、MEDIUMBLOB(0-16777215字節) 和 LONGBLOB(0-4294967295字節)
6.3 具體使用圖示
?
?
</center>
6.4 大字段的操作
創建保存大字段的表
CREATE TABLE user(
? ? `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵',
? ? `image` MEDIUMBLOB? COMMENT '圖片',
? ? `article` TEXT NOT NULL COMMENT '大字段文本'
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
存儲圖片/文本的例子
/*
* 保存大字段數據
*/
@Test
public void test01() throws ClassNotFoundException, SQLException, IOException {
? ? //加載數據庫驅動
? ? Class.forName("com.mysql.jdbc.Driver");
? ? //獲取數據庫連接
? ? Connection conn = DriverManager.getConnection("jdbc:mysql:///bigdata?characterEncoding=utf8", "root", "root");
? ? //準備sql語句
? ? String sql="INSERT INTO user(image,article) VALUES(?,?)";
? ? //獲取preparedStatement對象
? ? PreparedStatement ps = conn.prepareStatement(sql);
? ? //綁定參數
? ? //獲取二進制流
? ? InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("mysql.jpg");
? ? ps.setBinaryStream(1, inputStream, inputStream.available());
? ? //獲取文本流
? ? File file = new File("mysql.sql");
? ? FileReader reader = new FileReader(file);
? ? ps.setCharacterStream(2, reader, file.length());
? ? ps.executeUpdate();
? ? ps.close();
? ? conn.close();
}
讀取圖片/文本的例子
/*
* 查詢大字段數據
*/
@Test
public void test02() throws SQLException, ClassNotFoundException, IOException {
? ? //加載數據庫驅動
? ? Class.forName("com.mysql.jdbc.Driver");
? ? //獲取數據庫連接
? ? Connection conn = DriverManager.getConnection("jdbc:mysql:///bigdata?characterEncoding=utf8", "root", "root");
? ? //準備sql語句
? ? String sql="SELECT id,image,article FROM user WHERE id=?";
? ? //獲取preparedStatement對象
? ? PreparedStatement ps = conn.prepareStatement(sql);
? ? ps.setInt(1, 1);
? ? ResultSet resultSet = ps.executeQuery();
? ? if(resultSet.next()) {
? ? ? ? InputStream binaryStream = resultSet.getBinaryStream("image");
? ? ? ? Reader characterStream = resultSet.getCharacterStream("article");
? ? ? ? FileOutputStream outputStream = new FileOutputStream(new File("1.jpg"));
? ? ? ? byte[] b = new byte[1024];
? ? ? ? int len_=0;
? ? ? ? while((len_=binaryStream.read(b))!=-1) {
? ? ? ? ? ? outputStream.write(b, 0, len_);
? ? ? ? }
? ? ? ? System.out.println("=============");
? ? ? ? char[] c = new char[512];
? ? ? ? int len=0;
? ? ? ? while((len=characterStream.read(c))!=-1) {
? ? ? ? ? ? System.out.println(new String(c, 0,len));
? ? ? ? }
? ? }
}
第七章 封裝JDBC工具類
封裝獲取和關閉數據庫連接的工具類
①獲取數據庫連接
?? --加載數據庫驅動
?? --獲取數據庫連接
②關閉數據庫連接
?? --關閉ResultSet
?? --關閉PreparedStatement
?? --關閉Connection
代碼
public class JdbcUtils {
?
? ? private static final String URL="jdbc:mysql:///test";
? ? private static final String USER="root";
? ? private static final String PASSWORD="root";
? ? private static Connection connection=null;
? ? static {
? ? ? ? try {
? ? ? ? ? ? connection = DriverManager.getConnection(URL, USER, PASSWORD);
? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? /**
? ? * 獲取數據庫連接
? ? */
? ? public static Connection getConnection() {
? ? ? ? return connection;
? ? }
? ? /**
? ? * 關閉數據庫連接
? ? */
? ? public static void close(Connection conn) {
? ? ? ? if(conn!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? conn.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? /**
? ? * 關閉連接
? ? * @param conn
? ? * @param ps
? ? */
? ? public static void close(Connection conn,PreparedStatement ps) {
? ? ? ? if(ps!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ps.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(conn!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? conn.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? /**
? ? * 關閉連接
? ? * @param conn
? ? * @param ps
? ? * @param rs
? ? */
? ? public static void close(Connection conn,PreparedStatement ps,ResultSet rs) {
? ? ? ? if(rs!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? rs.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(ps!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ps.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(conn!=null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? conn.close();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
?
封裝操作數據庫Dao層的通用類
查詢單個對象
/*
* 查詢單個對象(采用JDK原生的API方式調用反射接口進行返回對象的封裝)
*/
public T get(Connection conn,String sql,Class<T> clazz,Object ...args) throws SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
? ? //聲明返回值
? ? T t=null;
? ? //將SQL進行預編譯
? ? PreparedStatement ps = conn.prepareStatement(sql);
? ? ResultSet rs = null;
? ? if(args!=null && args.length>0) {
? ? ? ? //進行參數綁定
? ? ? ? for(int i=0;i
? ? ? ? ? ? ps.setObject(i+1, args[i]);
? ? ? ? }
? ? ? ? rs=ps.executeQuery();
? ? }else {
? ? ? ? //執行綁定參數之后的SQL語句返回結果集對象
? ? ? ? rs=ps.executeQuery();
? ? }
? ? //獲取描述結果集對象的元數據信息
? ? ResultSetMetaData rsmd = rs.getMetaData();
? ? //獲取總列數
? ? int count = rsmd.getColumnCount();
? ? //如果存在結果集那么開始進行封裝
? ? if(rs.next()) {
? ? ? ? //通過反射創建對象
? ? ? ? t = clazz.newInstance();
? ? ? ? //循環獲取列對象
? ? ? ? for(int i=0;i
? ? ? ? ? ? //獲取列名(如果有別名獲取別名,沒有別名獲取列名)
? ? ? ? ? ? String columnName = rsmd.getColumnLabel(i+1);
? ? ? ? ? ? //獲取列值
? ? ? ? ? ? Object columnValue = rs.getObject(columnName);
? ? ? ? ? ? //通過反射獲取clazz對象里描述屬性的Field對象
? ? ? ? ? ? Field field = clazz.getDeclaredField(columnName);
? ? ? ? ? ? //開啟權限控制
? ? ? ? ? ? field.setAccessible(true);
? ? ? ? ? ? //給T對象屬性賦值
? ? ? ? ? ? field.set(t, columnValue);
? ? ? ? }
? ? }
? ? return t;
}
查詢對象列表
/*
* 查詢對象列表
* 不采用原生反射API進行對象封裝而是采用第三方提供的工具類進行封裝
* commons-beanutils-1.8.0.jar
* commons-logging-1.1.1.jar
* 需要這兩個jar包,進行對象封裝
*/
public List<T> getList(Connection conn,String sql,Class<T> clazz,Object ...args) throws SQLException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
? ? //聲明返回值
? ? List list = new ArrayList<>();
? ? //將SQL進行預編譯
? ? PreparedStatement ps = conn.prepareStatement(sql);
? ? ResultSet rs = null;
? ? if(args!=null && args.length>0) {
? ? ? ? //進行參數綁定
? ? ? ? for(int i=0;i
? ? ? ? ? ? ps.setObject(i+1, args[i]);
? ? ? ? }
? ? ? ? //執行綁定參數之后的SQL語句返回結果集對象
? ? ? ? rs=ps.executeQuery();
? ? }else {
? ? ? ? rs=ps.executeQuery();
? ? }
? ? //獲取描述結果集對象的元數據信息
? ? ResultSetMetaData rsmd = rs.getMetaData();
? ? //獲取總列數
? ? int count = rsmd.getColumnCount();
? ? //如果存在結果集那么開始進行封裝
? ? while(rs.next()) {
? ? ? ? T t = clazz.newInstance();
? ? ? ? for(int i=0;i
? ? ? ? ? ? //獲取列名
? ? ? ? ? ? String columnName = rsmd.getColumnLabel(i+1);
? ? ? ? ? ? //獲取列值
? ? ? ? ? ? Object columnValue = rs.getObject(columnName);
? ? ? ? ? ? //封裝數據到對象中
? ? ? ? ? ? PropertyUtils.setProperty(t, columnName, columnValue);
? ? ? ? }
? ? ? ? list.add(t);
? ? }
? ? return list;
}
第八章 數據庫連接池
8.1 連接池介紹
數據庫連接池的概念:負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是再重新建立一個連接來操作數據庫.
8.2 常見連接池
C3P0:比較古老的數據庫連接池
官網地址: https://www.mchange.com/projects/c3p0/
?
C3P0提供了多種創建數據庫連接的方式,根據官網任選其一即可
Druid:alibaba的基于Java的高效的數據庫連接池
官網地址: https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
8.3 C3P0連接池使用
ComboPooledDataSource pool = new ComboPooledDataSource();
pool.setDriverClass("com.mysql.jdbc.Driver");
pool.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc");
pool.setUser("root");
pool.setPassword("root");
第九章 DBUtils工具類
9.1 DBUtils介紹
DBUtils是apache的一個組件,算是一個輕量級的JDBC框架,官網地址
?
https://commons.apache.org/proper/commons-dbutils/
?
DbUtils是一個非常小的類庫,不需要花很長的時間去看他的API類或者是接口,只需要知道QueryRunner和ReulthSthand兩個/接口類即可
9.2 DBUtils使用
通過BeanHandler查詢一個ResultSet返回一個JavaBean對象(查詢單個對象)
QueryRunner run = new QueryRunner(dataSource);
?
ResultSetHandler<Person> h = new BeanHandler<Person>(Person.class);
?
Person p = run.query("SELECT * FROM Person WHERE name=?", h, "John Doe");
通過BeanListHandler查詢所有的ResultSet返回一組JavaBean列表
QueryRunner run = new QueryRunner(dataSource);
?
ResultSetHandler<List<Person>> h = new BeanListHandler<Person>(Person.class);
?
List<Person> persons = run.query("SELECT * FROM Person", h);
第十章 多線程安全問題
當前端多個用戶發送多個請求的時候,每一個請求都會建立一個數據庫連接,而一個用戶請求可能執行多條SQL語句,多次操作數據庫,在執行多條SQL語句時怎么保證一個用戶請求在一個事務管理內,如果不能保證在一個事務管理中就會出現線程安全問題,造成前后數據的不一致。保證線程安全的主要任務就是保證一個用戶請求中執行的多條SQL語句在一個數據庫連接中即可.還有一種情況實在使用數據庫連接池時候,由于數據庫連接池的鏈接是可以共用的,在一個用戶請求過來的時候由于有異常產生而需要事物回滾操作,但是在事務還沒有來得及回滾的時候其他的請求使用了這個連接池里的連接,進行了提交,這個時候在回滾就會沒有效果,造成的數據出錯
解決方案
public class JdbcUtil {
? ? private static ThreadLocal pool = new ThreadLocal<>();
? ? /**
? ? * 獲取當前請求線程上的Connection
? ? * @return
? ? */
? ? public static Connection getConnection() {
? ? ? ? Connection conn = pool.get();
? ? ? ? if(conn==null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? Class.forName("com.mysql.jdbc.Driver");
? ? ? ? ? ? ? ? conn = DriverManager.getConnection("", "", "");
? ? ? ? ? ? ? ? pool.set(conn);
? ? ? ? ? ? } catch (ClassNotFoundException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? } catch (SQLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return conn;
? ? }
? ? /**
? ? * 關閉當前請求線程上的Connection
? ? */
? ? public static void close(){
? ? Connection conn = pool.get();
? ? conn.close();//關閉連接
? ? pool.remove();//移除連接
? ? }
}