- 2024-11-10 14:34:59
- 8891 热度
- 0 评论
Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器,以下是包括在这个开源版本中的一些功能:
l 全面崩溃 / 重启恢复
l 兼容标准的SUN公司JTA API
l 嵌套事务
l 为XA和非XA提供内置的JDBC适配器
注释:XA:XA协议由Tuxedo首先提出的,并交给X/Open组织,作为资源管理器(数据库)与事务管理器的接口标准。Oracle、Informix、DB2和Sybase等各大数据库厂家都提供对XA的支持。XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。XA协议包括两套函数,以xa_开头的及以ax_开头的。
使用SpringBoot集成Atomikos时出现一个问题,提示大量Warn:
15:03:01.118 [restartedMain] WARN c.a.j.AtomikosConnectionProxy - [logWarning,24] - atomikos connection proxy for com.mysql.cj.jdbc.ConnectionImpl@3b8b4cb6: WARNING: transaction manager not running? 15:03:01.150 [restartedMain] WARN c.a.j.AtomikosConnectionProxy - [logWarning,24] - atomikos connection proxy for com.mysql.cj.jdbc.ConnectionImpl@3b8b4cb6: WARNING: transaction manager not running? 15:03:01.151 [restartedMain] WARN c.a.j.AtomikosConnectionProxy - [logWarning,24] - atomikos connection proxy for com.mysql.cj.jdbc.ConnectionImpl@3b8b4cb6: WARNING: transaction manager not running? ......
经过验证,多数据源事物正常使用,但是大量提示WARN,让我很不舒服。
它有个外国github的说法是这样的
但是我感觉不可能这么多年了还有这样的问题,最终找到答案,是因为我们在配置数据源时没有显示指定分布式事务管理器
如下代码,JTA 事务配置:
import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import com.atomikos.icatch.jta.UserTransactionImp; import com.atomikos.icatch.jta.UserTransactionManager; /** * JTA 事务配置 */ @Configuration public class AtomikosConfig { @Bean(name = "userTransaction") public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransactionImp = new UserTransactionImp(); userTransactionImp.setTransactionTimeout(10000); return userTransactionImp; } @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") public TransactionManager atomikosTransactionManager() throws Throwable { UserTransactionManager userTransactionManager = new UserTransactionManager(); userTransactionManager.setForceShutdown(false); return userTransactionManager; } @Bean(name = "transactionManager") @DependsOn({ "userTransaction", "atomikosTransactionManager" }) public PlatformTransactionManager transactionManager() throws Throwable { UserTransaction userTransaction = userTransaction(); TransactionManager atomikosTransactionManager = atomikosTransactionManager(); return new JtaTransactionManager(userTransaction, atomikosTransactionManager); } }
因为使用的是Druid,配置Druid多数据源:
import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.util.Utils; import com.atomikos.jdbc.AtomikosDataSourceBean; import com.ruoyi.common.enums.DataSourceType; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.config.properties.DruidProperties; import com.ruoyi.framework.datasource.DynamicDataSource; /** * druid 配置多数据源 */ @Configuration public class DruidConfig { public static final String MASTER = DataSourceType.MASTER.name(); public static final String SLAVE = DataSourceType.SLAVE.name(); @Autowired private DruidProperties druidProperties; @Bean @ConfigurationProperties("spring.datasource.druid.master") @DependsOn({ "transactionManager" }) public DataSource masterDataSource(Environment env) { String prefix = "spring.datasource.druid.master."; return getDataSource(env, prefix, MASTER); } @Bean @ConfigurationProperties("spring.datasource.druid.slave") @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") @DependsOn({ "transactionManager" }) public DataSource slaveDataSource(Environment env) { String prefix = "spring.datasource.druid.slave."; return getDataSource(env, prefix, SLAVE); } protected DataSource getDataSource(Environment env, String prefix, String dataSourceName) { Properties prop = build(env, prefix); AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource"); ds.setUniqueResourceName(dataSourceName); ds.setXaProperties(prop); return ds; } protected Properties build(Environment env, String prefix) { Properties prop = new Properties(); prop.put("url", env.getProperty(prefix + "url")); prop.put("username", env.getProperty(prefix + "username")); prop.put("password", env.getProperty(prefix + "password")); prop.put("initialSize", druidProperties.getInitialSize()); prop.put("minIdle", druidProperties.getMinIdle()); prop.put("maxActive", druidProperties.getMaxActive()); prop.put("maxWait", druidProperties.getMaxWait()); prop.put("timeBetweenEvictionRunsMillis", druidProperties.getTimeBetweenEvictionRunsMillis()); prop.put("minEvictableIdleTimeMillis", druidProperties.getMinEvictableIdleTimeMillis()); prop.put("maxEvictableIdleTimeMillis", druidProperties.getMaxEvictableIdleTimeMillis()); prop.put("validationQuery", druidProperties.getValidationQuery()); prop.put("testWhileIdle", druidProperties.isTestWhileIdle()); prop.put("testOnBorrow", druidProperties.isTestOnBorrow()); prop.put("testOnReturn", druidProperties.isTestOnReturn()); return prop; } @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource(DataSource masterDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(MASTER, masterDataSource); setDataSource(targetDataSources, SLAVE, "slaveDataSource"); return new DynamicDataSource(masterDataSource, targetDataSources); } /** * 设置数据源 * * @param targetDataSources 备选数据源集合 * @param sourceName 数据源名称 * @param beanName bean名称 */ public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) { try { DataSource dataSource = SpringUtils.getBean(beanName); targetDataSources.put(sourceName, dataSource); } catch (Exception e) { } } /** * 去除监控页面底部的广告 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { // 获取web监控页面的参数 DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); // 提取common.js的配置路径 String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); final String filePath = "support/http/resources/js/common.js"; // 创建filter进行过滤 Filter filter = new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); // 重置缓冲区,响应头不会被重置 response.resetBuffer(); // 获取common.js String text = Utils.readFromResource(filePath); // 正则替换banner, 除去底部的广告信息 text = text.replaceAll("<a.*?banner\"></a><br/>", ""); text = text.replaceAll("powered.*?shrek.wang</a>", ""); response.getWriter().write(text); } @Override public void destroy() { } }; FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(filter); registrationBean.addUrlPatterns(commonJsPattern); return registrationBean; } }
这里需要注意的是@DependsOn({ "transactionManager" })这个注解,需要给数据源显示指定为多数据源的JTA事物管理器。
END
0 评论
留下评论
热门标签
- Spring(403)
- Boot(208)
- Spring Boot(187)
- Spring Cloud(82)
- Java(82)
- Cloud(82)
- Security(60)
- Spring Security(54)
- Boot2(51)
- Spring Boot2(51)
- Redis(31)
- SQL(29)
- Mysql(25)
- Dalston(24)
- IDE(24)
- mongoDB(22)
- MVC(22)
- JDBC(22)
- IDEA(22)
- Web(21)
- CLI(20)
- Alibaba(19)
- SpringMVC(19)
- Docker(17)
- SpringBoot(17)
- Git(16)
- Eclipse(16)
- Vue(16)
- JPA(15)
- Apache(15)
- ORA(15)
- Tomcat(14)
- Linux(14)
- HTTP(14)
- Mybatis(14)
- Oracle(14)
- jdk(14)
- OAuth(13)
- Nacos(13)
- Pro(13)
- XML(13)
- JdbcTemplate(13)
- JSON(12)
- OAuth2(12)
- Data(12)
- int(11)
- Myeclipse(11)
- stream(11)
- not(10)
- Bug(10)
- Hystrix(9)
- ast(9)
- maven(9)
- Map(9)
- Swagger(8)
- APP(8)
- Bit(8)
- API(8)
- session(8)
- Window(8)
- windows(7)
- too(7)
- HTML(7)
- Github(7)
- JavaMail(7)
- Cache(7)
- File(7)
- IntelliJ(7)
- mail(7)
- Server(6)
- nginx(6)
- jar(6)
- ueditor(6)
- ehcache(6)
- UDP(6)
- RabbitMQ(6)
- and(6)
- star(6)
- Excel(6)
- Log4J(6)
- pushlet(6)
- apt(6)
- Freemarker(6)
- read(6)
- WebFlux(6)
- JSP(6)
- Bean(6)
- error(6)
- are(5)
- SVN(5)
- for(5)
- DOM(5)
- Sentinel(5)
- the(5)
- JWT(5)
- rdquo(5)
- PHP(5)
- Struts(5)
- string(5)
- script(5)