我试图将Spring引导指南中的管理事务示例扩展到两个数据源,但是@事务注释似乎只适用于其中一个数据源。
在"Application.java"中,我添加了两个数据源及其Jdbc模板的bean。在"BookingService.java"中,我使用了属于第二个数据源的JdbcTemboard。
这是我的“Application.java”:
package hello;
import javax.sql.DataSource;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@Bean
BookingService bookingService() {
return new BookingService();
}
@Primary
@Bean(name="datasource1")
@ConfigurationProperties(prefix="datasource1")
DataSource datasource1() {
return DataSourceBuilder.create().build();
}
@Bean(name="jdbcTemplate1")
@Autowired
JdbcTemplate jdbcTemplate1(@Qualifier ("datasource1") DataSource datasource) {
return new JdbcTemplate(datasource);
}
@Bean(name="datasource2")
@ConfigurationProperties(prefix="datasource2")
DataSource datasource2() {
return DataSourceBuilder.create().build();
}
@Bean(name="jdbcTemplate2")
@Autowired
JdbcTemplate jdbcTemplate2(@Qualifier ("datasource2") DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
log.info("Creating tables");
jdbcTemplate.execute("drop table BOOKINGS if exists");
jdbcTemplate.execute("create table BOOKINGS("
+ "ID serial, FIRST_NAME varchar(5) NOT NULL)");
return jdbcTemplate;
}
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
BookingService bookingService = ctx.getBean(BookingService.class);
bookingService.book("Alice", "Bob", "Carol");
Assert.assertEquals("First booking should work with no problem", 3,
bookingService.findAllBookings().size());
try {
bookingService.book("Chris", "Samuel");
}
catch (RuntimeException e) {
log.info("v--- The following exception is expect because 'Samuel' is too big for the DB ---v");
log.error(e.getMessage());
}
for (String person : bookingService.findAllBookings()) {
log.info("So far, " + person + " is booked.");
}
log.info("You shouldn't see Chris or Samuel. Samuel violated DB constraints, and Chris was rolled back in the same TX");
Assert.assertEquals("'Samuel' should have triggered a rollback", 3,
bookingService.findAllBookings().size());
try {
bookingService.book("Buddy", null);
}
catch (RuntimeException e) {
log.info("v--- The following exception is expect because null is not valid for the DB ---v");
log.error(e.getMessage());
}
for (String person : bookingService.findAllBookings()) {
log.info("So far, " + person + " is booked.");
}
log.info("You shouldn't see Buddy or null. null violated DB constraints, and Buddy was rolled back in the same TX");
Assert.assertEquals("'null' should have triggered a rollback", 3, bookingService
.findAllBookings().size());
}
}
下面是“BookingService.java”:
package hello;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Transactional;
public class BookingService {
private final static Logger log = LoggerFactory.getLogger(BookingService.class);
@Autowired
@Qualifier("jdbcTemplate2")
JdbcTemplate jdbcTemplate;
@Transactional
public void book(String... persons) {
for (String person : persons) {
log.info("Booking " + person + " in a seat...");
jdbcTemplate.update("insert into BOOKINGS(FIRST_NAME) values (?)", person);
}
};
public List<String> findAllBookings() {
return jdbcTemplate.query("select FIRST_NAME from BOOKINGS", new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString("FIRST_NAME");
}
});
}
}
这些是"application.yml"中的应用属性:
datasource1:
url: "jdbc:h2:~/h2/ds1;DB_CLOSE_ON_EXIT=FALSE"
username: "sa"
datasource2:
url: "jdbc:h2:~/h2/ds2;DB_CLOSE_ON_EXIT=FALSE"
username: "sa"
这里的“pom.xml”与管理事务中的相同。
当@主注释位于datasource2 bean上时,一切都按预期工作。当@主注释位于datasource1 bean上时,datasource2中的写入不是事务性的,并且会得到以下输出:
...
2016-05-27 16:01:23.775 INFO 884 --- [ main] hello.Application : So far, Alice is booked.
2016-05-27 16:01:23.775 INFO 884 --- [ main] hello.Application : So far, Bob is booked.
2016-05-27 16:01:23.775 INFO 884 --- [ main] hello.Application : So far, Carol is booked.
2016-05-27 16:01:23.775 INFO 884 --- [ main] hello.Application : So far, Chris is booked.
2016-05-27 16:01:23.775 INFO 884 --- [ main] hello.Application : You shouldn't see Chris or Samuel. Samuel violated DB constraints, and Chris was rolled back in the same TX
Exception in thread "main" 2016-05-27 16:01:23.776 INFO 884 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3901d134: startup date [Fri May 27 16:01:22 CEST 2016]; root of context hierarchy
java.lang.AssertionError: 'Samuel' should have triggered a rollback expected:<3> but was:<4>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:645)
at hello.Application.main(Application.java:84)
2016-05-27 16:01:23.778 INFO 884 --- [ Thread-2] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
所以“克里斯”没有退后。
我想这与正确初始化两个数据库有关。这是一只虫子,还是我遗漏了什么?
谢谢
我在《pplication.java》里加了两颗豆子:
@Bean(name="tm1")
@Autowired
DataSourceTransactionManager tm1(@Qualifier ("datasource1") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
@Bean(name="tm2")
@Autowired
DataSourceTransactionManager tm2(@Qualifier ("datasource2") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
并将"Booking Service.java"中的@Transactional更改为:
@Transactional("tm2")
因此,现在我们有两个资源本地事务管理器,每个数据源一个,它的工作原理与预期一致。
非常感谢迪纳姆先生!
在我的应用程序中,我配置了XML启动bean: 我还配置了事务管理: 并且具有自动连线的: 因此,它失败与异常: 我做错了什么?
问题内容: 我刚刚开始使用spring和hibernate进行项目。我的DAO图层类扩展了HibernateDaoSupport。我们没有使用注释。之前,我们使用了struts,因此我们使用了Session类提供的getTransaction,commit,rollback ..方法。我的要求非常简单,对于所有DAO类,如果有异常,则回滚,否则提交。请提出介绍spring交易管理的最简单方法。 问
我试图初始化管理SDK,但在服务号初始化中面临400个坏请求。它在我的开发窗口环境中工作得很好,但是当我在linux中部署时,我面临着这个问题。 我正在从属性文件读取文件路径。 我当时正试图发送推送通知,当时我正面临问题。 查出
问题内容: Spring框架在多大程度上适用于事务处理?我读过《 Spring In Action》一书中的建议,并提供了一些示例,这些示例创建了不用担心会话和事务管理的DAO方法,只需通过以XML设置会话工厂和事务模板,然后将它们连接到DAO中即可。另一方面,SpringSource.org的文档建议需要大量的XML和/或注释才能实现此目的。 真相是什么,我按照以下方式获取代码的最简单方法是什么
是否可以配置Spring批处理管理员来启动主作业和从作业。我们有一个进程作为主节点和3-4个从节点。 Spring batch admin在单独的JVM进程中运行,但所有Spring批处理作业都使用相同的批处理数据库模式。
主要内容:1.事务环境搭建,2.注意1.事务环境搭建 UserDao.java UserService.java 在Service后面加上了一个异常 TxConfig.java配置类 test 本来的数据 数据达到回滚的效果。 2.注意 1.在service方法上添加@Transactional注解 2.在配置类上加入@EnableTransactionManagement注解 开启事务管理器功能 3.在配置类中加入Platform