当一个service更新一条数据,但是在异步方法里,查询数据时候,不是最新的数据的???
示例(普通开启线程-当前线程有睡眠):
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
new Thread(() -> {
GoodsPO byId = this.getById("111");
//这个时候查询是没有提交事务的数据(也就是更新前的数据)
log.info("【测试goodspo】{}", JacksonUtils.obj2json(byId));
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("【==当前线程事务提交==】");
}
}
//打印
/**
【==当前线程事务开始==】
【测试goodspo】 未提交事务的数据
【==当前线程事务提交==】
*/
示例(普通开启线程-当前线程没有睡眠):
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
new Thread(() -> {
GoodsPO byId = this.getById("111");
//这个时候查询是提交事务的数据(也就是更新后的数据)
log.info("【测试goodspo】{}", JacksonUtils.obj2json(byId));
}).start();
log.info("【==当前线程事务提交==】");
}
}
//打印
/**
【==当前线程事务开始==】
【==当前线程事务提交==】
【测试goodspo】 已经提交事务的数据(更新后的数据)
*/
示例(springboot线程池@EnableAsync-@Async("executor")-):
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
//异步线程池方法
taskExecutor.asyncTest("111");
log.info("【==当前线程事务提交==】");
}
}
@Async("executor")
public void asyncTest(String s) {
GoodsPO byId = goodsMapper.selectById(s);
log.info("【测试goodspo】{}", JacksonUtils.obj2json(byId));
}
//打印
/**
【==当前线程事务开始==】
【==当前线程事务提交==】
【测试goodspo】 (本地环境是获取更新后的数据,其实线上环境是获取更新前的数据)
*/
(本地环境是获取更新后的数据,其实线上环境是获取更新前的数据)
解决上面问题
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
//异步线程池方法
taskExecutor.asyncTest("111");
log.info("【==当前线程事务提交==】");
}
}
@Async("executor")
public void asyncTest(String s) {
try {
long start = System.currentTimeMillis();
log.info("线程开始休眠start{}",start);
Thread.sleep(1000);
log.info("线程结束休眠end{}",System.currentTimeMillis() - start);
} catch (InterruptedException e) {
e.printStackTrace();
}
GoodsPO byId = goodsMapper.selectById(s);
log.info("【测试goodspo】{}", JacksonUtils.obj2json(byId));
}
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
//异步线程池方法
taskExecutor.asyncTest("111");
log.info("【==当前线程事务提交==】");
}
}
@Async("executor")
public void asyncTest(GoodsPO goodsPO) {
log.info("【测试goodspo】{}", JacksonUtils.obj2json(goodsPO));
}
注意:异步方法里的异常,不会影响外面事务的
进阶解决@Transactional 事务提交之后执行 @Async 修饰的异步方法
最近项目中遇到的问题:
俩个service方法, 方法A中调用方法B。
方法A核心业务涉及多张表的数据操作,事务采用注解:@Transactional(rollbackFor = Exception.class)。
方法B 比较耗时,为了不影响核心业务,方法B 用@Async注解,单独开启一个线程去异步执行。(方法B在另外一个类里边,不能和A在同一个类)。
出现的问题:
方法A的事务还没提交,方法B就执行了,导致方法B中查到的数据还是老数据。
当时想到的解决方案,方法A事务提交后再执行方法B
class A {
@Autowired
private B b;
@Transactional
public void updateA(..) {
insert(..);
update(..);
b.updateB(..);
}
}
class B {
@Async
public void updateB(..) {
update(..)
}
注意
方法A和方法B假如在同一个类中,则方法B的@Async注解会失效:
首先先解释下@Transactional注解失效原因:Spring在扫描bean的时候会扫描方法是否包含@Transactional注解,如果包含,spring会为这个bean动态生成一个子类(代理类proxy),代理类是继承原来的bean的。
此时,当前这个注解的方法被调用时候,实际上是由代理类调用的,代理类在调用之前就会启动Transaction事务。然而,如果这个方法被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来bean直接调用,所以就不会启动Transaction,我们看到的现象就是 @Transactional 注解无效。
@Transactional和@Async注解实现都是基于spirng的Aop,而AOP实现是基于动态代理实现的,故Async 失效的原理和原理是一样的。(都是因为同一个类其他方法调用时,没有通过代理类调用,所以注解失效)
代码
@Resource
private TaskExecutor taskExecutor;
@Transactional
@Override
public void test() {
log.info("【==当前线程事务开始==】");
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getIsDelete, 1).eq(GoodsPO::getId, "111"));
if(update) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void beforeCommit(boolean readOnly) {
log.info("【==当前事务提交前==】");
}
@Override
public void afterCommit() {
log.info("【==当前事务提交后==】");
//异步线程池方法
taskExecutor.asyncTest("111");
}
});
log.info("【==当前线程事务提交完成==】");
}
}
@Async("executor")
public void asyncTest(String s) {
GoodsPO byId = goodsMapper.selectById(s);
log.info("【测试goodspo】{}", JacksonUtils.obj2json(byId));
}
//打印
/**
【==当前线程事务开始==】
【==当前线程事务提交完成==】
【==当前事务提交前==】
【==当前事务提交后==】
【测试goodspo】 (事务提交后的数据)
*/
进阶解决@Transactional 事务提交之后执行 异步方法时,获取不到事务提交后的数据(@TransactionalEventListener注解)
Spring事务监听机制—使用@TransactionalEventListener处理数据库事务提交成功后再执行操作
/**
事件
* */
public class AcctypeEvent extends ApplicationEvent {
private String id;
public AcctypeEvent(Object source, String id) {
super(source);
this.id = id;
}
public String getId() {
return id;
}
}
定义事件监听器
/**
事件监听器
* */
@Component
public class AcctytpeEventListener {
@Resource
private TaskExecutor taskExecutor;
//监听劵批次事件
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
void updataAcctypeEvent(AcctypeEvent event) {
// String id = event.getId();//商品id
//查询最新的数据
taskExecutor.asyncTest();
}
}
发布事件
@Autowired
private ApplicationContext applicationContext;
@Transactional(rollbackFor = Exception.class)
@Override
public void test2() throws Exception {
log.info("【主线程名称】:{}",Thread.currentThread().getName());
//更新操作
boolean update = this.update(Wrappers.<GoodsPO>lambdaUpdate().set(GoodsPO::getApp, 66).eq(GoodsPO::getId, "0001059971"));
//发布事件,处理异步任务(查询最新数据,发送短信成功后更新状态)
applicationContext.publishEvent(new AcctypeEvent("我是和事务相关的事件,请事务提交后执行我","0001059971"));
}
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时