ShardingProxy插入Emoji表情报错

版本号: 4.1.1

报错: 

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1

经过万能的排除法后,发现当insert操作时,属性里包含emoji的话会报错,然后进而影响之后的所有update操作也会跟着报错

但是如果没有insert操作的话,直接update操作是不会报错的

目前社区已经有人提bug了,下一版应该会修复这个问题

目前有几种解决方案的思路

1: 官方修复

优点: 不用自己写代码

缺点:需要等

2. 去除emoji字符串

优点: 简单暴力且不用对历史数据进行处理

缺点: 无法存入emoji表情,需要emoji-java的jar包


    com.vdurmont
    emoji-java
    4.0.0

3. 在数据入库时对emoji表情转码,同样在出库时也进行转码

优点: 能保存emoji表情

缺点: 所有出库的地方都需要进行emoji转码,涉及面比较广,如果数据库本身就使用utf8mb4的话,这样处理就会有点多此一举,因为utf8mb4本身就支持emoji表情,那出库的地方就肯定需要对字符串进行emoji转码,不然就得对历史数据进行处理,才能去掉转码代码块,工作量也挺大的

4. 手动控制事务,先插入去除emoji表情的字符串,然后提交事务,再新建事务重新写入原来有emoji的字符串并进行修改

5. 通过异步事务监听进行处理,也是我接下来要讲的方法

优点: 冇

缺点: 要写代码,到时候还要删代码,同样需要emoji-java包,两次数据库操作

现在分享下个人的临时处理方案

我这边的对象都继承自MybatisPlus的Model对象,所以可以直接用Model的持久化方法 -> updateById()

核心注解: 

@Async: 异步注解,需要@EnableAsync支持

@Transactional: spring事务注解

@EventListener: 事件监听注解

@TransactionalEventListener: 事务事件监听注解

 

Demo:

import com.baomidou.mybatisplus.extension.activerecord.Model;
import org.springframework.context.ApplicationEvent;

/**
 * 事件监听对象
 */
public class EmojiEvent extends ApplicationEvent {

	private T source;

	public EmojiEvent(T source) {
		super(source);
		this.source = source;
	}

	@Override
	public T getSource() {
		return source;
	}
}
import com.baomidou.mybatisplus.extension.activerecord.Model;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 监听
 */
@Component
public class EmojiListen {

	@Async("emojiPool") // 设置线程池
	@Order
	@EventListener(EmojiEvent.class) // 监听事件对象
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) // 监听事务提交后执行
	public void run(EmojiEvent emojiEvent) {
		Model model = emojiEvent.getSource();
		model.updateById(); // Pojo对象继承自MybatisPlus的Model对象,所以可以使用Model.updateById();
	}

    /**
     * 线程池
     */
	@Bean
	public Executor emojiPool() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(10);
		executor.setMaxPoolSize(20);
		executor.setQueueCapacity(200);
		executor.setKeepAliveSeconds(60);
		executor.setThreadNamePrefix("emojiExecutor-");
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		return executor;
	}

}
@Service
public class test() {
    
    @Autoware
    private ApplicationEventPublisher publisher;

    @Transactional(rollbackFor = Throwable.class)
    public void save() {
        String emoji = ""; // emoji苹果表情
        // 伪代码
        Pojo pojo = new Pojo();
        pojo.setEmoji(EmojiUtil.removeAllEmojis(emoji)); // 先去掉emoji表情
        pojo.insert(); // 执行插入
        // 回写emoji表情并推入事件监听
        pojo.setEmoji(emoji);
        publisher.publishEvent(new EmojiEvent<>(pojo));
    }
}

之后它就会在事务提交后进行修改持久化操作

 

 

如果帮到你,请点个赞吧 O(∩_∩)O~

你可能感兴趣的:(ShardingProxy)