接
本文介绍使用spring-data-jpa连接mycat实现应用的读写分离.
系统环境
spring-boot 1.4.3-RELEASE
jdk1.8
进入正题
application.yml配置文件
这个很传统,指定mysql以及datasource就可以.
特别说一句:mycat跟应用是相互独立的,mycat后边的mysql集群对于应用来说就相当于一台单独的mysql server,所以,不要纠结与应用该用什么数据库连接工具
spring: application: name: mycat-jpa datasource: platform: mysql type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:8066/mall?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&useSSL=false username: root password: jiabin jpa: hibernate: ddl-auto: none show-sql: true
JpaTransactionConfig类文件
这个配置类是重点.
在使用mycat时需要关闭spring-data-jpa默认的事务管理机制. 原因如下:
mycat对于开启了事务的查询,插入等操作,都会走主库
spring-data-jpa默认的事务管理机制对查询操作执行的是
只读事务
,话说只读事务
也是事务啊
鉴于以上两个原因.我们就得使用enableDefaultTransactions = false
来关闭spring-data-jpa默认的事务管理机制.
好吧,既然我们关闭了默认的事务管理机制,我们就得使用@Transactional
来开启声明式事务处理.哈哈,也就是说,我们需要用添加@Transactional
注解的硬编码方式来实现事务管理.见SalesmanService
package jpa.mycat;import org.springframework.context.annotation.Configuration;import org.springframework.data.jpa.repository.config.EnableJpaRepositories;/** * Created by ssab on 17-1-4. */@EnableJpaRepositories(basePackages = "jpa.mycat", enableDefaultTransactions = false)@Configurationpublic class JpaTransactionConfig {}
弄懂了这两个配置,剩下的就简单了.
Salesman实体类
package jpa.mycat; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; /** * Created by ssab on 17-1-5. */ @Entity @Table(name = "salesman") public class Salesman { @Id @GenericGenerator(name = "idgen", strategy = "increment") @GeneratedValue(generator = "idgen") @Column(name = "id") private Long id;//业务员ID private String userNum;//工号 private String trueName;//真实姓名 private String address;//地址 private String avatarPicUrl;//头像的图片地址 private String telephone;//固定电话:区号-号码 private String mobile;//手机号码 private int disabled;//是否作废0否1是 private String remark;//备注 private String appUserId;//备用userId字段(外勤APP用) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserNum() { return userNum; } public void setUserNum(String userNum) { this.userNum = userNum; } public String getTrueName() { return trueName; } public void setTrueName(String trueName) { this.trueName = trueName; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getAvatarPicUrl() { return avatarPicUrl; } public void setAvatarPicUrl(String avatarPicUrl) { this.avatarPicUrl = avatarPicUrl; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public int getDisabled() { return disabled; } public void setDisabled(int disabled) { this.disabled = disabled; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public String getAppUserId() { return appUserId; } public void setAppUserId(String appUserId) { this.appUserId = appUserId; } @Override public String toString() { return "Salesman{" + "id=" + id + ", userNum='" + userNum + '\'' + ", trueName='" + trueName + '\'' + ", address='" + address + '\'' + ", avatarPicUrl='" + avatarPicUrl + '\'' + ", telephone='" + telephone + '\'' + ", mobile='" + mobile + '\'' + ", disabled=" + disabled + ", remark='" + remark + '\'' + ", appUserId='" + appUserId + '\'' + '}'; } }
SalesmanRepository
package jpa.mycat; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.List; /** * Created by ssab on 17-1-5. */ public interface SalesmanRepository extends JpaRepository<Salesman, Long> { Salesman save(Salesman salesman); @Query(value = "select * from salesman limit 0,18", nativeQuery = true) List<Salesman> findAll(); }
SalesmanService
package jpa.mycat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * Created by ssab on 17-1-5. */ @Service public class SalesmanService { @Autowired private SalesmanRepository repository; @Transactional(propagation = Propagation.REQUIRED) public Salesman save(Salesman salesman) { return repository.save(salesman); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public List<Salesman> findAll() { return repository.findAll(); } }
测试
SalesmanServiceTest
package jpa.mycat; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * Created by ssab on 17-1-5. */ @SpringBootTest @RunWith(SpringRunner.class) public class SalesmanServiceTest { @Autowired private SalesmanService service; @Test public void testFindAll() { service.findAll().forEach(salesman -> System.out.println(salesman.toString())); } @Test public void testSave(){ Salesman salesman = new Salesman(); salesman.setUserNum("3333333"); salesman.setTrueName("ssab"); salesman.setAddress("山东省莱芜市"); salesman.setMobile("152222222"); salesman.setDisabled(0); service.save(salesman); } }
运行testFindAll方法,查看mycat日志
注意看图中红框内的内容
好吧我们确定是走的从库.
运行testSave方法,查看mycat日志
从图中红框内的内容我们发现走的是主库.
总结
使用spring-data-jpa连接mycat的重点就在于关闭spring-data-jpa的默认事务管理机制并使用@Transactional注解来进行声明式事务管理.
注意这点就可以了.