create table account (
id int primary key auto_increment,
name varchar(20),
money double
);
insert into account values(null,'a',1000),(null,'b',1000);java
1、事務
事務的概念:事務是指邏輯上的一組操做,這組操做要麼同時完成要麼同時不完成.
事務的管理:默認狀況下,數據庫會自動管理事務,管理的方式是一條語句就獨佔一個事務.
若是須要本身控制事務也能夠經過以下命令開啓/提交/回滾事務
start transaction;
commit;
rollback;
JDBC中管理事務:
conn.setAutoCommit(false);
conn.commit();
conn.rollback();
SavePoint sp = conn.setSavePoint();
conn.rollback(sp);
事務的四大特性:一個事務具備的最基本的特性,一個設計良好的數據庫能夠幫咱們保證事務具備這四大特性(ACID)
原子性:原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。
一致性:若是事務執行以前數據庫是一個完整性的狀態,那麼事務結束後,不管事務是否執行成功,數據庫仍然是一個完整性狀態.
數據庫的完整性狀態:當一個數據庫中的全部的數據都符合數據庫中所定義的全部的約束,此時能夠稱數據庫是一個完整性狀態.
隔離性:事務的隔離性是指多個用戶併發訪問數據庫時,一個用戶的事務不能被其它用戶的事務所幹擾,多個併發事務之間數據要相互隔離。
持久性:持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即便數據庫發生故障也不該該對其有任何影響。
隔離性:
將數據庫設計成單線程的數據庫,能夠防止全部的線程安全問題,天然就保證了隔離性.可是若是數據庫設計成這樣,那麼效率就會極其低下.
數據庫中的鎖機制:
共享鎖:在非Serializable隔離級別作查詢不加任何鎖,而在Serializable隔離級別下作的查詢加共享鎖,
共享鎖的特色:共享鎖和共享鎖能夠共存,可是共享鎖和排他鎖不能共存
排他鎖:在全部隔離級別下進行增刪改的操做都會加排他鎖,
排他鎖的特色:和任意其餘鎖都不能共存
若是是兩個線程併發修改,必定會互相搗亂,這時必須利用鎖機制防止多個線程的併發修改
若是兩個線程併發查詢,沒有線程安全問題
若是兩個線程一個修改,一個查詢......
四大隔離級別:
Read uncommitted -- 不防止任何隔離性問題,具備髒讀/不可重複度/虛讀(幻讀)問題
Read committed -- 能夠防止髒讀問題,可是不能防止不可重複度/虛讀(幻讀)問題
Repeatable read -- 能夠防止髒讀/不可重複讀問題,可是不能防止虛讀(幻讀)問題
Serializable -- 數據庫被設計爲單線程數據庫,能夠防止上述全部問題
從安全性上考慮: Serializable>Repeatable read>read committed>read uncommitted
從效率上考慮: read uncommitted>read committed>Repeatable read>Serializable
真正使用數據的時候,根據本身使用數據庫的需求,綜合分析對安全性和對效率的要求,選擇一個隔離級別使數據庫運行在這個隔離級別上.
mysql 默認下就是Repeatable read隔離級別
oracle 默認下就是read committed個隔離級別
查詢當前數據庫的隔離級別:select @@tx_isolation;
設置隔離級別:set [global/session] transaction isolation level xxxx;其中若是不寫默認是session指的是修改當前客戶端和數據庫交互時的隔離級別,而若是使用golbal,則修改的是數據庫的默認隔離級別
髒讀:一個事務讀取到另外一個事務未提交的數據
a 1000
b 1000
----------
a:
start transaction;
update account set money=money-100 where name=a;
update account set money=money+100 where name=b;
----------
b:
start transaction;
select * from account;
a : 900
b : 1100
----------
a:
rollback;
----------
b:
start transaction;
select* from account;
a: 1000
b: 1000
不可重複讀:在一個事務內讀取表中的某一行數據,屢次讀取結果不一樣 --- 行級別的問題
a: 1000 1000 1000
b: 銀行職員
---------
b:start transaction;
select 活期存款 from account where name='a'; ---- 活期存款:1000
select 按期存款 from account where name='a'; ---- 按期存款:1000
select 固定資產 from account where name='a'; ---- 固定資產:1000
-------
a:
start transaction;
update accounset set 活期=活期-1000 where name='a';
commit;
-------
select 活期+按期+固定 from account where name='a'; --- 總資產:2000
commit;
----------
虛讀(幻讀):是指在一個事務內讀取到了別的事務插入的數據,致使先後讀取不一致 --- 表級別的問題
a: 1000
b: 1000
d: 銀行業務人員
-----------
d:
start transaction;
select sum(money) from account; --- 2000 元
select count(name) from account; --- 2 個
------
c:
start transaction;
insert into account values(c,4000);
commit;
------
select sum(money)/count(name) from account; --- 平均:2000元/個
commit;
------------
更新丟失問題:
兩個線程基於同一個查詢結果進行修改,後修改的人會將先修改人的修改覆蓋掉.
悲觀鎖:悲觀鎖悲觀的認爲每一次操做都會形成更新丟失問題,在每次查詢時就加上排他鎖
樂觀鎖:樂觀鎖會樂觀的認爲每次查詢都不會形成更新丟失.利用一個版本字段進行控制
查詢很是多,修改很是少,使用樂觀鎖
修改很是多,查詢很是少,使用悲觀鎖mysql
=================================================================================
2、數據庫鏈接池
手寫鏈接池:
改造conn的close方法
繼承
裝飾
!動態代理
web
開源數據源:
DBCP:
方式1: sql
BasicDataSource source = new BasicDataSource(); source.setDriverClassName("com.mysql.jdbc.Driver"); source.setUrl("jdbc:mysql:///day11"); source.setUsername("root"); source.setPassword("root");
方式2:數據庫
Properties prop = new Properties(); prop.load(new FileReader("dbcp.properties")); BasicDataSourceFactory factory = new BasicDataSourceFactory(); DataSource source = factory.createDataSource(prop);
配置文件中:tomcat
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///day11 username=root password=root
#<!-- 初始化鏈接 -->
initialSize=10安全
#最大鏈接數量
maxActive=50session
#<!-- 最大空閒鏈接 -->
maxIdle=20併發
#<!-- 最小空閒鏈接 -->
minIdle=5oracle
#<!-- 超時等待時間以毫秒爲單位 6000毫秒/1000等於60秒 -->
maxWait=60000
C3P0數據源:
方式1:
ComboPooledDataSource source = new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql:///day11"); source.setUser("root"); source.setPassword("root");
方式2:
ComboPooledDataSource source = new ComboPooledDataSource();
在類加載目錄下名稱爲c3p0-config.xml的配置文件中配置:
<c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///day11</property> <property name="user">root</property> <property name="password">root</property> </default-config> </c3p0-config>
tomcat內置的數據源(DBCP):
~1.如何爲tomcat配置數據源
~tomcat/conf/context.xml文件中配置<Context>配置在這個位置的信息將會被全部的web應用所共享
~tomcat/conf/[engin]/[Host]/context.xml文件中能夠配置<Context>標籤,這裏配置的信息將會被這臺虛擬主機中的全部web應用所共享
~tomcat/conf/server.xml文件中的<Host>標籤中配置<Context>標籤,這是web應用的第一種配置方式,在這個標籤中配置的信息將只對當前web應用起做用
~tomcat/conf/[engin]/[Host]/本身建立一個.xml文件,在這個文件中使用<Context>標籤配置一個web應用,這是web應用第二種配置方式,在這個<Context>標籤中配置的信息將只會對當前web應用起做用
~web應用還有第三種配置方式:將web應用直接放置到虛擬主機管理的目錄.此時能夠在web應用的META-INF文件夾下建立一個context.xml文件,在其中能夠寫<Context>標籤進行配置,這種配置信息將只會對當前web應用起做用
<Resource name="mySource" auth="Container" type="javax.sql.DataSource" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql:///day11" maxActive="8" maxIdle="4"/>
~2.若是在程序中獲取這個數據源
想要訪問jndi就必須在Servlet中才能執行下列代碼:
Context initCtx = new InitialContext(); Context jndi = (Context) initCtx.lookup("java:comp/env"); DataSource source = jndi.lookUp("mySource");