MyCat + JPA 读写分离

通过MyCat实现读写分离的需求,环境为springboot下的JPA。

MyCat版本为1.6

1.MySQL主从同步配置

2.下载安装MyCat

安装myCat

// 进入local文件夹
cd /usr/local

// 下载mycat安装包
wget http://dl.mycat.org.cn/1.6.7.5/2020-3-3/Mycat-server-1.6.7.5-test-20200303154735-linux.tar.gz
//解压
tar -zxvf Mycat-server-1.6.7.5-test-20200303154735-linux.tar.gz

cd mycat
useradd mycat
chown -R mycat:mycat /usr/local/mycat

添加环境变量

$ vim /etc/profile
// 在最后添加
MYCAT_HOME=/usr/local/mycat/mycat
PATH=$MYCAT_HOME/bin:$PATH
export PATH

// 使配置生效
$ source /etc/profile

mycat的启停命令

//查看状态
mycat status
// 启动
mycat start
// 关闭
mycat stop

3.myCat的配置

  • server.xml配置

这里是myCat的整体大面的配置,包含端口以及用户的配置。

拉到最下面,来看用户的配置。

// 默认提供了2个示例,一个读写默认用户,一个只读用户。
// 我们只需要用到一个主用户

// 配置mycat的账户、密码,springboot中的数据源就使用这里的账户密码

// 配置schemas,这是myCat的读写分离、分片规则等的主要配置,
// 这里的schemas只配置规则的ID,具体的规则是在另一个配置文件中

	<user name="root" defaultAccount="true">
		<property name="password">root</property>
		<property name="schemas">demo_db</property>
		<property name="defaultSchema">demo_db</property>
	</user>
  • schema.xml的配置

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
	
	<schema name="demo_db" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1" >
	</schema>
	
	<dataNode name="dn1" dataHost="dataHost220" database="demo_db" />
	<dataHost name="dataHost220" maxCon="1000" minCon="10" balance="3"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="hostM1" url="192.168.3.220:3306" user="root" password="root">
			<readHost host="hostS2" url="192.168.3.220:3307" user="root" password="root" />
		</writeHost>
	</dataHost>

</mycat:schema>

4.检查mycat是否配置完成

启动

mycat start

如果启动过程中,遇到问题,可以查看日志,在/usr/local/mycat/logs中的wrapper.logmycat.log

shcema的名字,最好和数据库的名字保持一致,包括大小写

测试:

在mycat中修改字段,查看主从库,都有改动。

在从库中修改字段,查看主库未改变,mycat有改变。

5.springboot配置

  • 关闭JPA的自动事务

JPA有自动事务,所有的更新语句、查询语句都有事务,这涉及到JPA的缓存机制,可以自己去了解。

任何带有事务的sql,mycat都会去走主库,而不是从库。

因此JPA的自动事务必须关闭。

在启动类上加如下注释,可以关闭JPA的默认事务

@SpringBootApplication
@EnableJpaRepositories(enableDefaultTransactions = false)
public class MydemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MydemoApplication.class, args);
    }

}
  • JPA的事务配置

JPA中的更新操作,必须有事务才能执行,因此我们需要给每一个更新操作加上事务。

方法一:

手动加事务,注解@Transactional

在service类中的每一个更新方法上,加事务注解

方法二:

通过配置类,统一添加事务,

com.zyy.*.service.*.*(..)表达式的意思是,com.zyy下的任意包中的service包中的任意类的任意方法,方法参数为任意个

@Aspect
@Configuration
public class TransactionalConfigForBoot {

    private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.zyy.*.service.*.*(..))";
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
        txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
        txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttr_REQUIRED_READONLY.setReadOnly(true);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("add*", txAttr_REQUIRED);
        source.addTransactionalMethod("create*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("delete*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);

        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值