The database is basically a single database in the monomer schema mode, so the essence of the application layer through spring transaction control is the support of the database to the transaction, without the transaction support of the database, spring cannot provide the transaction function. The way to implement transactions through spring also has declarative and programmatic transactions of two kinds, whichever is simpler to implement. Like the general business, the type is programmed in the following way:
1. configuration file
<!--transaction control-->
<bean id= "TransactionManager" class= " Org.springframework.jdbc.datasource.DataSourceTransactionManager ">
<property name=" DataSource "ref=" DataSource "/>
</bean>
<!-- Configure transaction propagation characteristics-->
<tx:advice id=" Txadvice " Transaction-manager= "TransactionManager" >
<tx:attributes>
<tx:method name= "save*" propagation= "REQUIRED"/>
<tx:method name= "update*" propagation= "REQUIRED"/> <tx:method name=
"delete*" propagation= "REQUIRED"/>
<tx:method name= "*" read-only= "true"/>
>
</tx:advice>
<!-- Configuring the class-->
<aop:config>
<aop:pointcut id= for participating transactions "Interceptorpointcuts" expression= "Execution (* com.orange.adminweb.service.*.* (..))" />
<aop:advisor pointcut-ref= "interceptorpointcuts" advice-ref= txadvice "/>"
</aop:config >
Java code under the 2.com.orange.adminweb.service package
public void updatebinding (String userid,string merchantid,order order) throws Exception {
//delete user
Userservice.delete (userId);
Delete Merchant
merchantservice.delete (Merchantid);
Update orders
orderservice.update (order);
}
There are only two things to note about programming like simple transactions:
1. The save*,update*,delete* of the above XML configuration means that the wildcard character begins with Save,update,delete (Com.orange.adminweb.service under the package) is enabled.
2. A method that begins with a save,update,delete (under Com.orange.adminweb.service) must continue to throw the anomaly out.
So, a lot of colleagues who are just starting out are basically writing code in this way, there is no problem, but recently the test has been reflected that there is a business (similar to the above) inconsistent data, simply is the data of several tables atomic inconsistency, I found the method class, opened the look, the scene is indeed a little bit different from the above, The following is the impersonation code.
private void Savesubscribe () {StringBuilder clientbuilder = new StringBuilder ();
Clientbuilder.append (GLOBALCONSTANT.GROUPID);
Clientbuilder.append ("@@@");
Clientbuilder.append ("Clientid_");
Clientbuilder.append (Uuidutil.get32uuid ());
String clientid=clientbuilder.tostring ();
Memorypersistence persistence = new memorypersistence ();
try {final mqttclient sampleclient = new Mqttclient (Globalconstant.broker, clientId, persistence);
Final Mqttconnectoptions connopts = new Mqttconnectoptions ();
SYSTEM.OUT.PRINTLN ("Connecting to Broker:" + globalconstant.broker);
String sign=macsignature.macsignature (Clientid.split ("@@@") [0], Globalconstant.secretkey);
Final string[] topicfilters=new string[]{globalconstant.topic + "/#"};
Final Int[]qos={1};
Connopts.setusername (Globalconstant.acesskey);
Connopts.setserveruris (new string[] {globalconstant.broker}); Connopts.setpassword (sign.ToCharArray ());
Connopts.setcleansession (FALSE);
Connopts.setkeepaliveinterval (100);
Sampleclient.setcallback (New Mqttcallback () {public void Connectionlost (Throwable throwable) {
Log.info ("Mqtt connection Lost");
Throwable.printstacktrace (); while (!sampleclient.isconnected ()) {try {sampleclient.connect (connopt
s);
Sampleclient.subscribe (Topicfilters,qos);
catch (Mqttexception e) {e.printstacktrace ();
try {thread.sleep (1000);
catch (Interruptedexception e) {e.printstacktrace (); }} public void messagearrived (String topic, mqttmessageMqttmessage) {try {saveorder (New String (Mqttmessage.getpayload ()));
catch (Exception e) {e.printstacktrace ();
}} public void Deliverycomplete (Imqttdeliverytoken imqttdeliverytoken) {
Log.ifo ("Deliverycomplete:" + Imqttdeliverytoken.getmessageid ());
}
});
Sampleclient.connect (connopts);
Sampleclient.subscribe (Topicfilters,qos);
}catch (Exception ex) {ex.printstacktrace (); }
}
The Saveorder method for manipulating three sheets is as follows:
private void Saveorder (String message) throws exception{
//Modify User
Userservice.updateuser (...);
Modify Merchant
merchantservice.updatemerchant (...);
Place order
Orderservice.saveorder (...);
}
Because the business itself, when the Saveorder method inside the modification of the user, modify the merchant, the order of any one method of exception, the Savesubscribe method does not roll back the data.
Focus on the code snippet in the Savesubscribe method:
Sampleclient.setcallback (New Mqttcallback () {public void Connectionlost (Throwable throwable) {
Log.info ("Mqtt connection Lost");
Throwable.printstacktrace (); while (!sampleclient.isconnected ()) {try {sampleclient.connect (connopt
s);
Sampleclient.subscribe (Topicfilters,qos);
catch (Mqttexception e) {e.printstacktrace ();
try {thread.sleep (1000);
catch (Interruptedexception e) {e.printstacktrace (); }} public void messagearrived (String topic, Mqttmessage mqttmessage
{try {Saveorder (Mqttmessage.getpayload ()) (new String); catch (excEption e) {e.printstacktrace ();
}} public void Deliverycomplete (Imqttdeliverytoken imqttdeliverytoken) {
Log.ifo ("Deliverycomplete:" + Imqttdeliverytoken.getmessageid ()); }
});
This inside has Setcallback callback, it inside of the exception is unable to go to throw outside, so will not roll back the data, simple Savesubscribe method is a method without transaction control.
In fact, this kind of business scenario is somewhat similar to our previous business requirements:
There is a aservice and bservice are configured transactions, Aservice called Bservice,bservice need to log, but when the bservice abnormal, found no log, The reason is that Aservice and bservice configure transactions with a parameter propagation, which is configured by default required
<tx:method name= "save*" propagation= "REQUIRED"/>
When using this policy, bservice will use Aservice transactions, so aservice rollback will roll back everything in the entire method body. So to solve this kind of business scenario requires bservice to configure independent transactions, regardless of the business logic aservice whether there is an exception, bservice log should be able to record success.
So solve the above Setcallback callback does not throw abnormal out of the problem, configuration modified to Saveorder configure independent transactions can solve the problem.
<tx:method name= "save*" propagation= "REQUIRED"/> <tx:method name= "
update*" propagation= "REQUIRED"/ >
<tx:method name= "delete*" propagation= "REQUIRED"/> <tx:method name= "Saveorder"
Requires_new "rollback-for=" Java.lang.Exception "/>
The solution to this problem, in the final analysis, does not pay attention to the spring transaction type, the specific business scenario should use a different transaction type, instead of using required, and finally post Spring's seven kinds of transactional propagation behavior types:
propagation_required--supports the current transaction and creates a new transaction if there are currently no transactions. This is the most common choice.
propagation_supports--supports the current transaction and executes it in a non transactional manner if there are currently no transactions.
propagation_mandatory--supports the current transaction and throws an exception if there are currently no transactions.
propagation_requires_new--creates a new transaction and suspends the current transaction if there is currently a transaction.
propagation_not_supported--performs an operation in a non transactional manner and suspends the current transaction if there is a current transaction.
propagation_never--executes in a non transactional manner and throws an exception if there is a current transaction.
propagation_nested--executes within a nested transaction if a transaction is currently present. If there is currently no transaction, a similar operation is performed with Propagation_required.