-
Notifications
You must be signed in to change notification settings - Fork 0
SpringBoot DB
Just follow the common practice to setup the related url/username/pwd/driver etc.
spring.datasource.url=jdbc:mysql://localhost:3306/xxx_hub?useSSL=false&characterEncoding=utf8
spring.datasource.username=xxx_u
spring.datasource.password=yyy1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- enable db tx by adding annotation @EnableTransactionManagement to your configuration class or main application class
- add @Transactional to the method where you expect transaction. It supports adjusts default behaviors to set the parameters, e.g. @Transactional(RollbackFor=Exception.class). See related document.
Special note: your tx maybe does work if the @Transactional is added on a method which is NOT invoked by a auto wired bean. see:https://stackoverflow.com/questions/37310550/spring-transaction-management-not-working-with-spring-boot-mybatis @Transactional只有在Autowired bean直接调用才行(间接调用都不行!!) 如果你的事物注解在方法上不生效,而在类上就生效,则一定是这问题! 上面这个链接讲的比较清楚。我下面给个间接调用不生效的例子,方便我们理解。
Here is an example
@Component
class App{
@Autowired X x
public void doSomething(){
x.insertDataDirectly(); // the tx does work
x.insertDataInDirectly(); //the tx does NOT work, although @Transactional method is used finally. Because the @Transactional method is NOT invoked by proxied bean directly.
}
}
@Component
class X{
@Transactional
public void insertDataDirectly(){
db.insert...
}
//外部调用这个方法的发,事物并不生效,虽然内部的方法添加了@Transactional注解。
public void insertDataInDirectly(){
insertDataDirectly();
}
}
A workaround for above problem. But the workaround is NOT easy to use since it makes code complex. Try to review your business logic and confirm whether you can add @Transactional on the bean and be called directly. 一个比较绕的解决办法.在下面的代码中,因为txWapper是autowired,所以spring proxy能够成功解析到。进而事物能够生效。这个方法我测试过了。但是要重新考虑,能不能把Transactional直接加在最外面的方法上。否则这个解决办法太绕了。
注意-容易形成循环依赖 - X依赖TxWrapper,TxWrapper调用X的方法,则会出现问题(TxWrapper的父引用为null)。别用普通内部类了
@Component
class X{
@Autowired
private TxWrapper txWrapper;
@Component
static class TxWrapper{
@Transactional
public void insertDataDirectly(){
db.insert...
}
}
//外部调用这个方法的发,事物并不生效,虽然内部的方法添加了@Transactional注解。
public void insertDataInDirectly(){
txWrapper.insertDataDirectly();
}
}
- 这个Transactional的方法必须是public的(试过了-https://stackoverflow.com/questions/3037006/starting-new-transaction-in-spring-bean)
- 另外,一个生效的Transactional注解调用,可以调用多个含有mapper/dao的子调用,事物仍在存在/生效(不用声明另外的Transactional注解)。 相反,如果这些子方法声明了Transactional注解,则还需要查看Propergation的东西。如果业务不太复杂,尽量避免。
工具:如何识别当前方法的事物是否已经开启? http://blog.timmattison.com/archives/2012/04/19/tips-for-debugging-springs-transactional-annotation/ 这个链接提供了一个工具方法,相当好用
//http://blog.timmattison.com/archives/2012/04/19/tips-for-debugging-springs-transactional-annotation/
import java.lang.reflect.InvocationTargetException;
public class DebugUtils {
private static final boolean transactionDebugging = true;
private static final boolean verboseTransactionDebugging = true;
public static void showTransactionStatus(String message) {
System.out.println(((transactionActive()) ? "[+] " : "[-] ") + message);
}
// Some guidance from: http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1
public static boolean transactionActive() {
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Class tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
Boolean isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
return isActive;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// If we got here it means there was an exception
throw new IllegalStateException("ServerUtils.transactionActive was unable to complete properly");
}
public static void transactionRequired(String message) {
// Are we debugging transactions?
if (!transactionDebugging) {
// No, just return
return;
}
// Are we doing verbose transaction debugging?
if (verboseTransactionDebugging) {
// Yes, show the status before we get to the possibility of throwing an exception
showTransactionStatus(message);
}
// Is there a transaction active?
if (!transactionActive()) {
// No, throw an exception
throw new IllegalStateException("Transaction required but not active [" + message + "]");
}
}
}