day16的內容有點無聊,但是還是硬着頭皮聽了,希望能早點過度到ssm的學習。
一、事務的概念
事務指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。
二、如何在jdbc中控制事務
在Jdbc中主要由以下三個語句控制事務:
(1)Connection.setAutoCommit(false); 開始事務
(2)Connection.rollback(); 回滾事務
(3)Connection.commit(); 提交事務
其中回滾事務的操作爲:
(1)設置回滾點:Savepoint sp = conn.setSavepoint();
(2)提交回滾請求:Conn.rollback(sp);
(3)提交事務:Conn.commit(); (回滾後必須提交事務)
三、事務的四大特性(ACID)
原子性(Atomicity)原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
一致性(Consistency)事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。
隔離性(Isolation)事務的隔離性是多個用戶併發訪問數據庫時,數據庫爲每一個用戶開啓的事務,不能被其他事務的操作數據所幹擾,多個併發事務之間要相互隔離。
持久性(Durability)持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。
四、事務的四大隔離級別
事務的隔離級別如果不引起重視,就會引發一系列問題,比如說髒讀,幻讀,不可重複讀:
(1)髒讀:指一個事務讀取了另外一個事務未提交的數據。
(2)不可重複讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同。
(3)虛讀(幻讀):是指在一個事務內讀取到了別的事務插入的數據,導致前後讀取不一致。
數據庫共定義了四種隔離級別:
(1)Serializable:可避免髒讀、不可重複讀、虛讀情況的發生。(串行化)
(2)Repeatable read:可避免髒讀、不可重複讀情況的發生。(可重複讀)
(3)Read committed:可避免髒讀情況發生(讀已提交)。
(4)Read uncommitted:最低級別,以上情況均無法保證。(讀未提交)
在mysql中有以下兩種語句來操作隔離級別:
(2)select @@tx_isolation 查詢當前事務隔離級別
五、從鏈接池中獲取鏈接
傳統方法獲取鏈接的缺點:用戶每次請求都需要向數據庫獲得鏈接,而數據庫創建連接通常需要消耗相對較大的資源,創建時間也較長,並且極易造成數據庫服務器內存溢出、宕機。
我們獲取鏈接的方式有以下三種:
1.使用動態代理技術構建鏈接池中的connection。
public class JdbcPool implements DataSource {
private static LinkedList<Connection> list = new LinkedList<Connection>();
static{
try{
InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
Class.forName(driver);
//爲了演示,循環輸出鏈接
for(int i=0;i<10;i++){
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println("獲取到了鏈接" + conn);
list.add(conn);
}
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public Connection getConnection() throws SQLException {
//proxyConnection.commit() proxyConnection.rollback
if(list.size()>0){
final Connection conn = list.removeFirst(); //myconnection.commit
System.out.println("池大小是" + list.size());
return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {//調用重寫的close方法
if(!method.getName().equals("close")){
return method.invoke(conn, args);
}else{
list.add(conn);
System.out.println(conn + "被還給池了!!");
System.out.println("池大小爲" + list.size());
return null;
}
}
});
}else{
throw new RuntimeException("對不起,數據庫忙");
}
}
/*
用包裝設計模式對某個對象進行增強
1.寫一個類,實現與被增強對象(mysql的connection)相同的接口
2、定義一個變量,指向被增強對象
3、定義一個構造方法,接收被增強對象
4、覆蓋想增強的方法
5、對於不想增強的方法,直接調用被增強對象的方法
*/
class MyConnection implements Connection{
private Connection conn;
private List pool;
public MyConnection(Connection conn,List pool){
this.conn = conn;
this.pool = pool;
}
public void close() throws SQLException {
pool.add(conn);
}} //其他沒有重寫的方法在這裏省略
也有一些開源組織提供了數據源的獨立實現:
DBCP 數據庫連接池
C3P0 數據庫連接池
2.DHCP技術獲取鏈接
DBCP 是 Apache 軟件基金組織下的開源連接池實現,使用DBCP數據源,應用程序應在系統中增加如下兩個 jar 文件:
(1)Commons-dbcp.jar:連接池的實現
(2)Commons-pool.jar:連接池實現的依賴庫
Tomcat 的連接池正是採用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。
首先配置資源文件:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true
username=root
password=root
initialSize=10 #初始值
maxActive=50#最大鏈接激活數
maxIdle=20#最大等待連接中的數量
minIdle=5#最小等待連接中的數量
maxWait=60000#最大等待毫秒數
connectionProperties=useUnicode=true;characterEncoding=UTF8
defaultAutoCommit=true #配置事務是否自動提交
defaultTransactionIsolation=READ_UNCOMMITTED #配置事務隔離級別
配置JdbcUtils_DHCP
package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class JdbcUtils_DBCP {
private static DataSource ds = null;
static{
try{
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties prop = new Properties();
prop.load(in);
BasicDataSourceFactory factory = new BasicDataSourceFactory();
ds = factory.createDataSource(prop);
System.out.println(ds);
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
public static void release(Connection conn,Statement st,ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
3.C3P0獲取鏈接池
C3P0的配置文件不是放在資源文件中的,而是放在xml中的,該xml放在src目錄下。
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--默認配置-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
<!--找mysql-->
<named-config name="oracle">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config> <!--找oracle-->
注意:在寫url的時候需要轉義字符。
獲取鏈接的工具類:
package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource ds = null;
static{
try{
ds = new ComboPooledDataSource();
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
public static void release(Connection conn,Statement st,ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
綜上C3P0最好用。(下班了!!!!)