有可能在Spring中获取给定对象的代理吗?我需要调用子类的函数.但是,显然,当我直接打电话时,方面不适用.这是一个例子:
public class Parent {
public doSomething() {
Parent proxyOfMe = Spring.getProxyOfMe(this); // (please)
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}
public class Child extends Parent {
@Secured("president")
public void sayHello() {
System.out.println("Hello Mr. President");
}
}
Run Code Online (Sandbox Code Playgroud)
我找到了实现这一目标的方法.它有效,但我认为不是很优雅:
public class Parent implements BeanNameAware {
@Autowired private ApplicationContext applicationContext;
private String beanName; // Getter
public doSomething() {
Parent proxyOfMe = applicationContext.getBean(beanName, Parent.class);
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}
Run Code Online (Sandbox Code Playgroud) 众所周知,当你代理一个对象时,比如当你用Spring/EJB创建一个具有事务属性的bean时,甚至当你用一些框架创建一个局部模拟时,代理对象也不知道,并且内部调用没有被重定向,然后没有截获......
这就是为什么如果你在Spring做类似的事情:
@Transactionnal
public void doSomething() {
doSomethingInNewTransaction();
doSomethingInNewTransaction();
doSomethingInNewTransaction();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomethingInNewTransaction() {
...
}
Run Code Online (Sandbox Code Playgroud)
当你打电话给doSomething时,除了主要的一个之外,你期望有3个新的交易,但实际上,由于这个问题,你只能得到一个......
所以我想知道你是如何处理这些问题的...
我实际上处在一个我必须处理复杂的事务系统的情况,我没有看到任何比将服务分成许多小服务更好的方法,因此我肯定会通过所有代理...
这让我很困扰,因为所有的代码属于同一个功能域,不应该拆分......
我发现这个相关问题的答案很有趣: Spring - @Transactional - 后台会发生什么?
Rob H说我们可以在服务中注入spring代理,并调用proxy.doSomethingInNewTransaction(); 代替.它很容易做到并且有效,但我真的不喜欢它......
侯云峰说:
所以我编写了自己的CglibSubclassingInstantiationStrategy和代理创建器版本,以便它将使用CGLIB生成一个真正的子类,该子类将调用委托给它的超级而不是另一个实例,Spring现在正在这样做.所以我可以自由地注释任何方法(只要它不是私有的),并且从我称之为这些方法的地方,它们将被处理.好吧,我仍然要付出代价:1.我必须列出我想要启用新CGLIB子类创建的所有注释.2.由于我现在正在生成子类,因此无法对最终方法进行注释,因此无法截获最终方法.
他说"现在哪个春天在做什么"是什么意思?这是否意味着现在拦截了内部交易呼叫?
你觉得哪个更好?
当您需要某些事务粒度时,是否拆分了类?或者你使用上面的一些解决方法?(请分享)
我正在学习如何使用 JPA 和 Hibernate 以及 MySQL 数据库创建 REST API,我看到了这个 @Transactional 注释。有人能解释一下这个注解有什么用吗?
例如我有这个简单的 DAO 类:
@Repository
public class EmployeeDAOHibernateImpl implements EmployeeDAO {
// define field for entitymanager
private EntityManager entityManager;
// set up constructor injection
@Autowired
public EmployeeDAOHibernateImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
@Transactional
public List<Employee> findAll() {
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
// create a query
Query<Employee> theQuery =
currentSession.createQuery("from Employee", Employee.class);
// execute query and get result list
List<Employee> employees = theQuery.getResultList(); …Run Code Online (Sandbox Code Playgroud) 我在我的应用程序中使用spring和hibernate并使用spring事务.
所以我在方法和带有数据库查询方法的DAO层上有注释@transaction的服务层.
@Transactional(readOnly = false)
public void get(){
}
Run Code Online (Sandbox Code Playgroud)
问题是当我想在数据库中保存一个对象时,我必须@Transaction在DAO层方法结束时使用.为什么?
我想如果我有注释@ transaction,那么spring应该在完成服务方法时自动提交事务.
DAO层:
public BaseEntity saveEntity(BaseEntity entity) throws Exception {
try {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(entity);
session.flush();
} catch (HibernateException he) {
throw new Exception("Failed to save entity " + entity);
}
return entity;
}
Run Code Online (Sandbox Code Playgroud)
服务层:
@Transactional(readOnly = false)
public BaseEntity saveEntity(BaseEntity entity) throws Exception {
return dao.saveEntity(entity);
}
Run Code Online (Sandbox Code Playgroud)
弹簧配置:
<context:property-placeholder properties-ref="deployProperties" />
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Activate Spring Data JPA repository support -->
<jpa:repositories base-package="com" /> …Run Code Online (Sandbox Code Playgroud) 我知道这可能是重复的,具有讽刺意味的是,在我开始阅读这里和那里之前,我知道我知道它是什么(无需说出来但我仍然会说,请纠正我错在哪里):
它减轻程序员必须使用transaction.begin()和transaction.begin().如果你有一个调用两个DAO方法的方法,通常每个方法都包含commit()并transaction.begin 包含实际操作并调用它们,那么它将导致两个事务(如果前面的dao方法也应该回滚,则可能存在回滚问题).但是,如果你用transaction.commit你的方法,然后这些人DAO呼叫将被包裹在一个单一的@transactional- begin()周期.当然,如果你使用commit() DAO,一定不要使用@Transactional和begin() 方法我认为.
我有以下实现。
@Transactional
public void saveAndGenerateResult(Data data) {
saveDataInTableA(data.someAmountForA);
saveDataInTableB(data.someAmountForB);
callAnAggregatedFunction(data);
}
public void saveDataInTableA(DataA a) {
tableARepository.saveAndFlush(a);
}
public void saveDataInTableA(DataB b) {
tableBRepository.saveAndFlush(b);
}
public void callAnAggregatedFunction() {
// Do something based on the data saved from the beginning in Table A and Table B
}
Run Code Online (Sandbox Code Playgroud)
重要的saveAndFlush是使数据立即可供callAnAggregatedFunction函数使用,以获取汇总结果并将其保存到另一个表中。这就是为什么我不使用save据我所知不会立即将事务刷新到数据库中的函数的原因。
但是,我@Transactional在函数上使用了注释saveAndGenerateResult,因为在发生任何故障的情况下,我想回退在该函数中完成的数据库事务,通常通过@Transactional在方法上进行注释可以确保发生任何故障。
在这种特定情况下会发生什么情况?我正在使用saveAndFlush哪种方法将数据立即刷新到数据库表中,并且如果最后一个函数(即callAnAggregatedFunction)无法将数据写入表中,将回退表A和表B中的先前写入操作吗?
众所周知,bean的方法的自调用在没有AspectJ的Spring中是行不通的。
看到这个问题例如,
我认为这是因为 Spring 创建的代理使用延迟模式调用目标对象的方法。像这样:
class MyClass {
@Autowired
private MyClass self; // actually a MyProxy instance
@Transactional // or any other proxy magic
public void myMethod() {}
public void myOtherMethod() {
this.myMethod(); // or self.myMethod() to avoid self-invokation problem
}
}
class MyProxy extends MyClass { // or implements MyInterface if proxyMode is not TARGET_CLASS and MyClass also implements MyInterface
private final MyClass delegate;
@Override
public void myMethod() {
// some proxy magic: caching, transaction management etc …Run Code Online (Sandbox Code Playgroud) 传播设置是必需的。
@Transactional(propagation = Propagation.REQUIRED)
Run Code Online (Sandbox Code Playgroud)
事务是读/写的。
这些在什么场景下使用?请给我举例说明
当我使用spring服务并且我想通过spring存储库更新几个数据库表时,我是否需要添加@Transactional来确保我是事务性和回滚还是已经存在?如果是,我是否需要将其添加到类级别或方法?
java ×7
spring ×7
hibernate ×4
jpa ×2
spring-aop ×2
spring-boot ×2
transactions ×2
aop ×1
ejb ×1
java-ee ×1
proxy ×1
spring-jdbc ×1