请参阅代码.
当我调用方法@Async loadMarkUpPCT()时,数据不会被提交到表中.它表现得好像是非牵引性的.
当我从loadMarkUpPCT(Class 1)中删除@Async时,即非异步,然后提交数据并按预期正常:transactional)
我期待与@Async和@Transactional有相同的结果,但它不是.请解释或我做错了什么?
编辑:我刚编辑发布代码+日志
流程:AppDataLoaderController调用AppDataLoaderService调用DataMigrationService调用JpaDataMigrationDao
package concepts.web.rest.resource.spring.impl;
@Controller
@RequestMapping("/appdataloader")
public class AppDataLoaderController {
@RequestMapping("/loadMarkupPct")
@ResponseStatus(HttpStatus.ACCEPTED)
public void loadMarkUpPCT() {
try {
this.appDataLoaderService.loadMarkUpPCT();
} catch (ServiceException e) {
e.printStackTrace();
}
}
package concepts.service.impl;
@Service("appDataLoaderService")
public class AppDataLoaderServiceImpl implements AppDataLoaderService {
@Async
@Override
public void loadMarkUpPCT() throws ServiceException {
logger.debug("@Async loadMarkUpPCT");
dataMigrationService.loadMarkUpPCT();
}
package concepts.service.impl;
@Service
@Scope("prototype")
public class DataMigrationServiceImpl implements DataMigrationService {
@Override
public void loadMarkUpPCT() throws ServiceException {
// TODO Auto-generated method stub
Assert.notNull(markUpPCTDataLoader);
List<MarkUpPCT> markUpPCTs=markUpPCTDataLoader.getMarkupCoef(); …Run Code Online (Sandbox Code Playgroud) 我需要在更新数据时通过JMS向外部系统发布通知事件.我想这样做是在同一个事务中完成的,因为对象被提交到数据库以确保完整性.
Spring-data-rest发出的ApplicationLifecycle事件似乎是实现此逻辑的逻辑位置.
@org.springframework.transaction.annotation.Transactional
public class TestEventListener extends AbstractRepositoryEventListener<Object> {
private static final Logger LOG = LoggerFactory.getLogger(TestEventListener.class);
@Override
protected void onBeforeCreate(Object entity) {
LOG.info("XXX before create");
}
@Override
protected void onBeforeSave(Object entity) {
LOG.info("XXX before save");
}
@Override
protected void onAfterCreate(Object entity) {
LOG.info("XXX after create");
}
@Override
protected void onAfterSave(Object entity) {
LOG.info("XXX after save");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这些事件发生在tx开始和提交之前和之后.
08 15:32:37.119 [http-nio-9000-exec-1] INFO n.c.v.vcidb.TestEventListener - XXX before create
08 15:32:37.135 [http-nio-9000-exec-1] TRACE o.s.t.i.TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
08 15:32:37.432 [http-nio-9000-exec-1] …Run Code Online (Sandbox Code Playgroud) 我们将Spring配置中的Spring事务配置为:
<tx:jta-transaction-manager/>
Run Code Online (Sandbox Code Playgroud)
我收集这意味着Spring将自动发现底层的JTA实现.因此,当我们启动JBoss时,我们会在Spring搜索时看到这些消息:
[JtaTransactionManager] [ ] No JTA TransactionManager found at fallback JNDI location [java:comp/Tran
sactionManager]
javax.naming.NameNotFoundException: TransactionManager not bound
<<Big stack trace>>
<<More of the same>>
Run Code Online (Sandbox Code Playgroud)
然后最终看到:
[JtaTransactionManager] [ ] JTA TransactionManager found at fallback JNDI location [java:/Transaction
Manager]
[JtaTransactionManager] [ ] Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserT
ransaction@1f78dde
Run Code Online (Sandbox Code Playgroud)
问题是 - 我们如何编辑我们的<tx:jta-transaction-manager/>标签以显式配置java:/Transaction ManagerJTA实现,以便我们避免日志中的所有这些堆栈跟踪?(我不想只改变Log4J日志记录级别)
更新:我<tx:jta-transaction-manager/>用下面的配置替换它似乎工作..我猜这是好的?
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager"/>
</bean>
Run Code Online (Sandbox Code Playgroud) 我们有一个在JBoss 4.2.3上运行的应用程序,使用Spring 2.5.2和Hibernate 3.2.6.ga. 这是在Linux JEE01 2.6.16.60-0.54.5-smp上运行,使用自己的用户.在另一台机器上写入Oracle 10G数据库.
我们正在使用标准视图 - >服务 - > dao分层.每个dao都使用@Repository注释.
这一切都是全天候运行而没有太多问题,但是每隔几天,有时几天,整个系统都会进入一个糟糕的状态,再也无法将任何内容写入数据库.这些堆栈跟踪显示在日志中:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not
allowed in read-only mode (FlushMode.NEVER/MANUAL):
Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction
definition.
Run Code Online (Sandbox Code Playgroud)
我们扫描了整个系统,系统中有一个位置,其中flushmode临时设置为MANUAL,之后finally块将其设置回原始值.这是因为我们不希望在运行此查询之前将状态刷新到数据库.所以我们不能轻易改变这一点.普通的FlushMode设置为AUTO,在几个地方我们暂时将其设置为COMMIT并再次将其切换回默认值.
只有服务器重新启动才能将系统恢复到正常工作状态.
问题是:为什么系统将所有事务设置为只读/手动刷新模式?我用Google搜索了这个,但找不到解决方法.
这是我们的spring和hibernate配置(仅显示相关部分):
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="datasourceName" />
</property>
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<tx:advice id="txAdvice" transaction-manager="txManager" >
<!-- the transactional semantics... -->
<tx:attributes >
<!-- all methods …Run Code Online (Sandbox Code Playgroud) 所以我有以下内容:
public interface MyService {
@PreAuthorize("hasPermission(T(Name).OBJ, T(Action).GET)")
MyObj getObj(String id);
}
Run Code Online (Sandbox Code Playgroud)
@Service
public class MyServiceImpl implements MyService {
@Override
@Transactional
public MyObj getObj(String id){
return dao.get(id);
}
}
Run Code Online (Sandbox Code Playgroud)
@Controller
public class MyController {
@Resource(name="myServiceImpl")
private MyService service;
public MyObj getObj(String id){
return service.getObj(id);
}
}
Run Code Online (Sandbox Code Playgroud)
getObj(id)调用该方法时,首先将所有内容包装在事务中,然后检查授权.是否可以保留此配置并首先让Spring检查授权,然后在用户获得授权的情况下创建事务?
我花了很多钱寻找答案,找不到任何东西.
从春季参考文档
Spring建议您只使用@Transactional注释来注释具体类(以及具体类的方法),而不是注释接口.您当然可以将@Transactional注释放在接口(或接口方法)上,但这只能在您使用基于接口的代理时按预期工作.Java注释不是从接口继承的事实意味着如果您使用基于类的代理(proxy-target-class ="true")或基于编织的方面(mode ="aspectj"),那么事务设置是代理和编织基础设施无法识别,并且该对象不会被包装在事务代理中,这将是非常糟糕的.
虽然它只涉及接口,但抽象类也被认为是非具体的.
所以,如果我有一个抽象类
public abstract class BaseService{
//here is a concrete method
@Transactional
public void updateData{
//do stuff using dao layer
}
Run Code Online (Sandbox Code Playgroud)
以及扩展该类的具体类
public class SpecialService extends BaseService{
//body of class
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我specialService.updateData()从我的控制器类调用它将是事务性的吗?
我有一个基于Spring的应用程序.我让Spring完成了所有的@Transactional魔法,只要我操作映射到Java对象的实体,一切都运行正常.
但是,当我想在未映射到任何Java实体的表上执行某些自定义作业时,我陷入困境.前段时间,我找到了一个执行自定义查询的解决方案,如下所示:
// em is instance of EntityManager
em.getTransaction().begin();
Statement st = em.unwrap(Connection.class).createStatement();
ResultSet rs = st.executeQuery("SELECT custom FROM my_data");
em.getTransaction().commit();
Run Code Online (Sandbox Code Playgroud)
当我使用@PersistenceContext注释从Spring注入的实体管理器尝试这个时,我收到了几乎明显的异常:
java.lang.IllegalStateException:
Not allowed to create transaction on shared EntityManager -
use Spring transactions or EJB CMT instead
Run Code Online (Sandbox Code Playgroud)
我终于设法提取非共享的实体管理器,如下所示:
@Inject
public void myCustomSqlExecutor(EntityManagerFactory emf){
EntityManager em = emf.createEntityManager();
// the em.unwrap(...) stuff from above works fine here
}
Run Code Online (Sandbox Code Playgroud)
不过,我发现这种解决方案既不舒适也不优雅.我只是想知道在这个Spring-transactional驱动的环境中是否还有其他方法可以运行自定义SQL查询?
对于那些好奇的人 - 当我尝试在我的应用程序和相关论坛中同时创建用户帐户时出现了这个问题 - 我不希望论坛的用户表被映射到我的任何Java实体.
我用ReplicationDriver使用mysql主/从复制(写入主服务器并读取到从服务器).我的连接URL如下:
"jdbc:mysql:replication://master:3306,slave1:3307,slave2:3308/sampledb?allowMasterDownConnections=true"
Run Code Online (Sandbox Code Playgroud)
我使用Spring + Spring MyBatis模块.
我已将事务标记为readOnly,如下所示:
@Override
@Transactional(rollbackFor=Exception.class,readOnly=true)
public Sample getSample(SampleKey sampleKey) throws SampleException {
//Call MyBastis based DAO with "select" queries.
}
Run Code Online (Sandbox Code Playgroud)
但是当我看到事务/ db日志时,它表明即使是"readOnly"事务,ReplicationDriver也会首先命中master.注意"获取连接"和"释放JDBC连接"行.
为什么会这样?
1)无论是否为只读查询,JDBC驱动程序是否仍然"ping"master以检查它是否存在然后转到slave以进行实际查询?
2)如果readOnly = true,Spring是否设置了底层Connection对象的readOnly(true)?
2014-03-19 12:32:28,280 DEBUG [http-8080-2] [AbstractPlatformTransactionManager.java:365] - Creating new transaction with name [com.rakuten.gep.foo.businesslogic.impl.SampleBusinessLogicImpl.getSample]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '',-java.lang.Exception
2014-03-19 12:32:28,390 DEBUG [http-8080-2] [DataSourceTransactionManager.java:204] - Acquired Connection [jdbc:mysql://master:3306/, UserName=root@10.174.10.72, MySQL Connector Java] for JDBC transaction
CACHED DAO
Trying to retrive from the Cache
2014-03-19 12:32:31,334 DEBUG [http-8080-2] [Slf4jImpl.java:47] - ooo Using Connection [jdbc:mysql://slave1:3307/, UserName=root@10.174.10.72, …Run Code Online (Sandbox Code Playgroud) 我有一个方法'databaseChanges',它以迭代的方式调用2个操作:A,B.'A'第一,'B'最后."A"和"B"可以是Ç reate,û PDATE d elete功能在我的永久存储,Oracle数据库11g.
比方说,
'A'更新表Users中的记录,属性zip,其中id = 1.
'B'在表爱好中插入记录.
场景:已调用databaseChanges方法,'A'操作并更新记录.'B'运行并尝试插入记录,发生了某种情况,抛出了异常,异常是冒泡到databaseChanges方法.
预期: 'A'和'B'没有任何改变."A"所做的更新将会回滚.'B'没有改变任何东西,嗯......有一个例外.
实际: 'A'更新似乎没有回滚.'B'没有改变任何东西,嗯......有一个例外.
一些代码
如果我有连接,我会做类似的事情:
private void databaseChanges(Connection conn) {
try {
conn.setAutoCommit(false);
A(); //update.
B(); //insert
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (Exception ei) {
//logs...
}
} finally {
conn.setAutoCommit(true);
}
}
Run Code Online (Sandbox Code Playgroud)
问题:我没有连接(请参阅带问题的标签)
我试过了:
@Service
public class SomeService implements ISomeService {
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
@Autowired
private NamedParameterJdbcTemplate npjt;
@Transactional
private void databaseChanges() throws Exception {
A(); …Run Code Online (Sandbox Code Playgroud) 我有下一个错误: nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.Model.entities, could not initialize proxy - no Session
我的Model实体:
class Model {
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "model", orphanRemoval = true)
@Cascade(CascadeType.ALL)
@Fetch(value = FetchMode.SUBSELECT)
public Set<Entity> getEntities() {
return entities;
}
public void addEntity(Entity entity) {
entity.setModel(this);
entities.add(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个服务类:
@Service
@Transactional
class ServiceImpl implements Service {
@Override
public void process(Model model) {
...
model.addEntity(createEntity());
...
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用其他服务方法调用服务:
@Override
@JmsListener(destination = …Run Code Online (Sandbox Code Playgroud) spring ×8
java ×5
hibernate ×2
jboss ×2
jpa ×2
jdbc ×1
jdbctemplate ×1
jta ×1
mysql ×1
oracle ×1
spring-boot ×1
transactions ×1