你好,我來先回答你的第一個問題:
成都創(chuàng)新互聯(lián)專注于洛陽網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供洛陽營銷型網(wǎng)站建設(shè),洛陽網(wǎng)站制作、洛陽網(wǎng)頁設(shè)計(jì)、洛陽網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造洛陽網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供洛陽網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
通常多數(shù)據(jù)源,在spring中配置如下,如果你想切換環(huán)境ENV 的值,在property中
bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
property name="ignoreResourceNotFound" value="true"/property
property name="ignoreUnresolvablePlaceholders" value="true"/property
property name="nullValue" value="NULL"/property
property name="locations"
list
valuejdbc.properties/value
/list
/property
/bean
bean id="dataSource" class="com.spring.dao.JDBCConfig"
property name="driverClassName" value="${${Env}.jdbc.driverClassName}"/property
property name="url" value="${${Env}.jdbc.url}"/property
property name="username" value="${${Env}.jdbc.username1}"/property
property name="password" value="${${Env}.jdbc.password}"/property
/bean
jdbc.properties
*****************************
Env=PROD
jdbc.driverClassName=${${Env}.jdbc.driverClassName}
jdbc.url=${${Env}.jdbc.url}
jdbc.username=${${Env}.jdbc.username}
jdbc.password=${${Env}.jdbc.password}
######### JDBC Configuration for DEV Environment ###############
DEV.jdbc.driverClassName=com.mysql.jdbc.Driver
DEV.jdbc.url=jdbc:mysql://localhost:3306/devportal
DEV.jdbc.username=DEVuser
DEV.jdbc.password=DEVpwd
######### JDBC Configuration for UAT Environment ############
UAT.jdbc.driverClassName=com.mysql.jdbc.Driver
UAT.jdbc.url=jdbc:mysql://localhost:3306/UATportal
UAT.jdbc.username=UATuser
UAT.jdbc.password=UATpwd
########## JDBC Configuration for PROD Environment ############
PROD.jdbc.driverClassName=com.mysql.jdbc.Driver
PROD.jdbc.url=jdbc:mysql://localhost:3306/portal
PROD.jdbc.username=root
PROD.jdbc.password=admin,
我這里有三套環(huán)境,分別是DEV,UAT和PROD,這種方式可以靈活切換的。
我再回答你的第二個問題:
還請你去這里看下,很詳細(xì),不過是英文的哦
分布式事務(wù)是指操作多個數(shù)據(jù)庫之間的事務(wù),在tomcat下是沒有分布式事務(wù)的,可以借助于第三方Jotm和Automikos實(shí)現(xiàn),下面就寫一個使用Jotm實(shí)現(xiàn)分布事務(wù)的例子,如有不足,請各位大大指點(diǎn):
Dao及實(shí)現(xiàn),先寫出一個interface再去實(shí)現(xiàn)他,可能有些人覺得直接寫實(shí)現(xiàn)類多好,但我還是建議為了結(jié)構(gòu)清晰,增強(qiáng)代碼的可讀性,可維護(hù)性還是先寫接口再去實(shí)現(xiàn)的好:
先寫一個interface,定義要實(shí)現(xiàn)的方法:
實(shí)現(xiàn)接口,傳入一個String ds來判斷調(diào)用哪個JdbcTemplate:
service及實(shí)現(xiàn):
還是接口與他的實(shí)現(xiàn):
持久化的操作:
applicationContext.xml
基本的spring配置以及Jotm bean;
JTA事務(wù)管理器,數(shù)據(jù)源datasourceA和datasourceB配置:
事務(wù)切面配置aop,通知配置以及dao,service配置:
單元測試,在實(shí)際項(xiàng)目中就是寫一個controller:
當(dāng)我們在生產(chǎn)線上用一臺服務(wù)器來提供數(shù)據(jù)服務(wù)的時候,我會遇到如下的兩個問題:
1)一臺服務(wù)器的性能不足以提供足夠的能力服務(wù)于所有的網(wǎng)絡(luò)請求。
2)我們總是害怕我們的這臺服務(wù)器停機(jī),造成服務(wù)不可用或是數(shù)據(jù)丟失。
于是我們不得不對我們的服務(wù)器進(jìn)行擴(kuò)展,加入更多的機(jī)器來分擔(dān)性能上的問題,以及來解決單點(diǎn)故障問題。 通常,我們會通過兩種手段來擴(kuò)展我們的數(shù)據(jù)服務(wù):
1)數(shù)據(jù)分區(qū):就是把數(shù)據(jù)分塊放在不同的服務(wù)器上(如:uid % 16,一致性哈希等)。
2)數(shù)據(jù)鏡像:讓所有的服務(wù)器都有相同的數(shù)據(jù),提供相當(dāng)?shù)姆?wù)。
對于第一種情況,我們無法解決數(shù)據(jù)丟失的問題,單臺服務(wù)器出問題時,會有部分?jǐn)?shù)據(jù)丟失。所以,數(shù)據(jù)服務(wù)的高可用性只能通過第二種方法來完成——數(shù)據(jù)的冗余存儲(一般工業(yè)界認(rèn)為比較安全的備份數(shù)應(yīng)該是3份,如:Hadoop和Dynamo)。 但是,加入更多的機(jī)器,會讓我們的數(shù)據(jù)服務(wù)變得很復(fù)雜,尤其是跨服務(wù)器的事務(wù)處理,也就是跨服務(wù)器的數(shù)據(jù)一致性。這個是一個很難的問題。 讓我們用最經(jīng)典的Use Case:“A帳號向B帳號匯錢”來說明一下,熟悉RDBMS事務(wù)的都知道從帳號A到帳號B需要6個操作:
從A帳號中把余額讀出來。
對A帳號做減法操作。
把結(jié)果寫回A帳號中。
從B帳號中把余額讀出來。
對B帳號做加法操作。
把結(jié)果寫回B帳號中。
為了數(shù)據(jù)的一致性,這6件事,要么都成功做完,要么都不成功,而且這個操作的過程中,對A、B帳號的其它訪問必需鎖死,所謂鎖死就是要排除其它的讀寫操作,不然會有臟數(shù)據(jù)的問題,這就是事務(wù)。那么,我們在加入了更多的機(jī)器后,這個事情會變得復(fù)雜起來:
1)在數(shù)據(jù)分區(qū)的方案中:如果A帳號和B帳號的數(shù)據(jù)不在同一臺服務(wù)器上怎么辦?我們需要一個跨機(jī)器的事務(wù)處理。也就是說,如果A的扣錢成功了,但B的加錢不成功,我們還要把A的操作給回滾回去。這在跨機(jī)器的情況下,就變得比較復(fù)雜了。
2)在數(shù)據(jù)鏡像的方案中:A帳號和B帳號間的匯款是可以在一臺機(jī)器上完成的,但是別忘了我們有多臺機(jī)器存在A帳號和B帳號的副本。如果對A帳號的匯錢有兩個并發(fā)操作(要匯給B和C),這兩個操作發(fā)生在不同的兩臺服務(wù)器上怎么辦?也就是說,在數(shù)據(jù)鏡像中,在不同的服務(wù)器上對同一個數(shù)據(jù)的寫操作怎么保證其一致性,保證數(shù)據(jù)不沖突?
同時,我們還要考慮性能的因素,如果不考慮性能的話,事務(wù)得到保證并不困難,系統(tǒng)慢一點(diǎn)就行了。除了考慮性能外,我們還要考慮可用性,也就是說,一臺機(jī)器沒了,數(shù)據(jù)不丟失,服務(wù)可由別的機(jī)器繼續(xù)提供。 于是,我們需要重點(diǎn)考慮下面的這么幾個情況:
1)容災(zāi):數(shù)據(jù)不丟、節(jié)點(diǎn)的Failover
2)數(shù)據(jù)的一致性:事務(wù)處理
3)性能:吞吐量 、 響應(yīng)時間
前面說過,要解決數(shù)據(jù)不丟,只能通過數(shù)據(jù)冗余的方法,就算是數(shù)據(jù)分區(qū),每個區(qū)也需要進(jìn)行數(shù)據(jù)冗余處理。這就是數(shù)據(jù)副本:當(dāng)出現(xiàn)某個節(jié)點(diǎn)的數(shù)據(jù)丟失時可以從副本讀到,數(shù)據(jù)副本是分布式系統(tǒng)解決數(shù)據(jù)丟失異常的唯一手段。所以,在這篇文章中,簡單起見,我們只討論在數(shù)據(jù)冗余情況下考慮數(shù)據(jù)的一致性和性能的問題。簡單說來:
1)要想讓數(shù)據(jù)有高可用性,就得寫多份數(shù)據(jù)。
2)寫多份的問題會導(dǎo)致數(shù)據(jù)一致性的問題。
3)數(shù)據(jù)一致性的問題又會引發(fā)性能問題
這就是軟件開發(fā),按下了葫蘆起了瓢。
一致性模型
說起數(shù)據(jù)一致性來說,簡單說有三種類型(當(dāng)然,如果細(xì)分的話,還有很多一致性模型,如:順序一致性,F(xiàn)IFO一致性,會話一致性,單讀一致性,單寫一致性,但為了本文的簡單易讀,我只說下面三種):
1)Weak 弱一致性:當(dāng)你寫入一個新值后,讀操作在數(shù)據(jù)副本上可能讀出來,也可能讀不出來。比如:某些cache系統(tǒng),網(wǎng)絡(luò)游戲其它玩家的數(shù)據(jù)和你沒什么關(guān)系,VOIP這樣的系統(tǒng),或是百度搜索引擎(呵呵)。
2)Eventually 最終一致性:當(dāng)你寫入一個新值后,有可能讀不出來,但在某個時間窗口之后保證最終能讀出來。比如:DNS,電子郵件、Amazon S3,Google搜索引擎這樣的系統(tǒng)。
3)Strong 強(qiáng)一致性:新的數(shù)據(jù)一旦寫入,在任意副本任意時刻都能讀到新值。比如:文件系統(tǒng),RDBMS,Azure Table都是強(qiáng)一致性的。
從這三種一致型的模型上來說,我們可以看到,Weak和Eventually一般來說是異步冗余的,而Strong一般來說是同步冗余的,異步的通常意味著更好的性能,但也意味著更復(fù)雜的狀態(tài)控制。同步意味著簡單,但也意味著性能下降。 好,讓我們由淺入深,一步一步地來看有哪些技術(shù):
Master-Slave
首先是Master-Slave結(jié)構(gòu),對于這種加構(gòu),Slave一般是Master的備份。在這樣的系統(tǒng)中,一般是如下設(shè)計(jì)的:
1)讀寫請求都由Master負(fù)責(zé)。
2)寫請求寫到Master上后,由Master同步到Slave上。
從Master同步到Slave上,你可以使用異步,也可以使用同步,可以使用Master來push,也可以使用Slave來pull。 通常來說是Slave來周期性的pull,所以,是最終一致性。這個設(shè)計(jì)的問題是,如果Master在pull周期內(nèi)垮掉了,那么會導(dǎo)致這個時間片內(nèi)的數(shù)據(jù)丟失。如果你不想讓數(shù)據(jù)丟掉,Slave只能成為Read-Only的方式等Master恢復(fù)。
當(dāng)然,如果你可以容忍數(shù)據(jù)丟掉的話,你可以馬上讓Slave代替Master工作(對于只負(fù)責(zé)計(jì)算的節(jié)點(diǎn)來說,沒有數(shù)據(jù)一致性和數(shù)據(jù)丟失的問題,Master-Slave的方式就可以解決單點(diǎn)問題了) 當(dāng)然,Master Slave也可以是強(qiáng)一致性的, 比如:當(dāng)我們寫Master的時候,Master負(fù)責(zé)先寫自己,等成功后,再寫Slave,兩者都成功后返回成功,整個過程是同步的,如果寫Slave失敗了,那么兩種方法,一種是標(biāo)記Slave不可用報(bào)錯并繼續(xù)服務(wù)(等Slave恢復(fù)后同步Master的數(shù)據(jù),可以有多個Slave,這樣少一個,還有備份,就像前面說的寫三份那樣),另一種是回滾自己并返回寫失敗。(注:一般不先寫Slave,因?yàn)槿绻麑慚aster自己失敗后,還要回滾Slave,此時如果回滾Slave失敗,就得手工訂正數(shù)據(jù)了)你可以看到,如果Master-Slave需要做成強(qiáng)一致性有多復(fù)雜。
Master-Master
Master-Master,又叫Multi-master,是指一個系統(tǒng)存在兩個或多個Master,每個Master都提供read-write服務(wù)。這個模型是Master-Slave的加強(qiáng)版,數(shù)據(jù)間同步一般是通過Master間的異步完成,所以是最終一致性。 Master-Master的好處是,一臺Master掛了,別的Master可以正常做讀寫服務(wù),他和Master-Slave一樣,當(dāng)數(shù)據(jù)沒有被復(fù)制到別的Master上時,數(shù)據(jù)會丟失。很多數(shù)據(jù)庫都支持Master-Master的Replication的機(jī)制。
另外,如果多個Master對同一個數(shù)據(jù)進(jìn)行修改的時候,這個模型的惡夢就出現(xiàn)了——對數(shù)據(jù)間的沖突合并,這并不是一件容易的事情??纯碊ynamo的Vector Clock的設(shè)計(jì)(記錄數(shù)據(jù)的版本號和修改者)就知道這個事并不那么簡單,而且Dynamo對數(shù)據(jù)沖突這個事是交給用戶自己搞的。就像我們的SVN源碼沖突一樣,對于同一行代碼的沖突,只能交給開發(fā)者自己來處理。(在本文后后面會討論一下Dynamo的Vector Clock)
Two/Three Phase Commit
這個協(xié)議的縮寫又叫2PC,中文叫兩階段提交。在分布式系統(tǒng)中,每個節(jié)點(diǎn)雖然可以知曉自己的操作時成功或者失敗,卻無法知道其他節(jié)點(diǎn)的操作的成功或失敗。當(dāng)一個事務(wù)跨越多個節(jié)點(diǎn)時,為了保持事務(wù)的ACID特性,需要引入一個作為協(xié)調(diào)者的組件來統(tǒng)一掌控所有節(jié)點(diǎn)(稱作參與者)的操作結(jié)果并最終指示這些節(jié)點(diǎn)是否要把操作結(jié)果進(jìn)行真正的提交(比如將更新后的數(shù)據(jù)寫入磁盤等等)。
看你是什么事務(wù),jdbc事務(wù),還是分布式事務(wù),還是容器事務(wù)
1,編程式事務(wù)管理(jdbc的事務(wù)是綁定在connection上的)
Connection conn = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID","username","password");
conn.setAutoCommit(false); //取消自動提交
PreparedStatement ps = conn.prepareCall("update something");
ResultSet rs = ps.executeQuery();
conn.commit(); //手動提交
}
catch (Exception e)
{
conn.rollback();
e.printStackTrace();
}
finally
{
conn.close();
}
2,聲明式事務(wù)
先在工程的application.xml配置文件中添加如下代碼,開啟事務(wù)
!-- 聲明式事務(wù)控制配置 --
tx:annotation-driven transaction-manager="txManager"/
bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
property name="datasource" ref="bassDataSource"/property
/bean
然后在你需要開啟事務(wù)的接口前面添加注解
@Transactional(rollbackFor = IOException.class)
public void add(String name) throws IOException
{
System.out.println("可以再類里和方法里面添加事務(wù)注解0~0");
throw new IOException();
}
直接調(diào)用接口方法就好
分布式事務(wù)處理(mysql貌似在5.X之后才支持) 的話,
1.可以直接使用spring+atomikos框架進(jìn)行管理
參考:
就不貼測試代碼了,自己看著配置吧
2,使用JTA(Java Transaction API)進(jìn)行分布式事務(wù)管理(測試代碼如下)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
//分布式事務(wù)處理
public class transferAccount
{
@SuppressWarnings("null")
public void testTransferAccount()
{
UserTransaction userts = null;
Connection connA = null;
PreparedStatement psA = null;
InitialContext context = null;
Connection connB = null;
PreparedStatement psB = null;
try
{
//獲得事務(wù)管理對象
userts = (UserTransaction) context.lookup("java:comp/UserTransaction");
//獲取兩個數(shù)據(jù)庫
connA = getDataSourceA().getConnection();
connB = getDataSourceB().getConnection();
//開啟事務(wù)
userts.begin();
//sql語句
psA = connA.prepareStatement("我加1");
psB = connB.prepareStatement("我減1");
//執(zhí)行sql
psA.executeUpdate();
psB.executeUpdate();
//事務(wù)提交
userts.commit();
} catch (Exception e)
{
try
{
userts.rollback();
} catch (IllegalStateException | SecurityException
| SystemException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
finally
{
try
{
psA.close();
psB.close();
connA.close();
connB.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
public DataSource getDataSourceA()
{
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("mysql");
dataSource.setServerName("server");
dataSource.setPortNumber(1433);
dataSource.setUser("test");
dataSource.setPassword("test");
return dataSource;
}
public DataSource getDataSourceB()
{
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("mysql");
dataSource.setServerName("server");
dataSource.setPortNumber(1435);
dataSource.setUser("test1");
dataSource.setPassword("test1");
return dataSource;
}
}
網(wǎng)頁題目:java分布式事務(wù)代碼 java分布式事務(wù)解決方案
文章出自:http://muchs.cn/article4/doshpoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、微信公眾號、微信小程序、品牌網(wǎng)站建設(shè)、小程序開發(fā)、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)