百度多方参考终于配出我自己的了,以下仅供参考

参考https://www.cnblogs.com/cjsblog/p/9712457.html

代码

首先数据源配置

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#第一个数据源
spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3307/dab?useUnicode=true&characterEncoding=utf-8
spring.datasource.master.username=root
spring.datasource.master.password=root
#第二个数据源只读账户
spring.datasource.slave1.jdbc-url=jdbc:mysql://localhost:3308/dab?useUnicode=true&characterEncoding=utf-8
spring.datasource.slave1.username=root
spring.datasource.slave1.password=root
#第三个数据源只读账户
spring.datasource.slave2.jdbc-url=jdbc:mysql://localhost:3309/dab?useUnicode=true&characterEncoding=utf-8
spring.datasource.slave2.username=root
spring.datasource.slave2.password=root #连接池参数,初始数、最大数、最小数、获取连接等待超时时间(毫秒)
spring.datasource.initial-size=5
spring.datasource.max-active=20
spring.datasource.min-idle=5
spring.datasource.max-wait=60000

启动类

我的dao和mapper分开的dao放的JPA的持久层,mapper放的mybatis的持久层

@EnableSwagger2
@SpringBootApplication
@EnableJpaRepositories(basePackages = { "com.bling.dab.dao" }, entityManagerFactoryRef = "entityManagerFactoryPrimary", transactionManagerRef = "transactionManagerPrimary")
@EnableTransactionManagement
@MapperScan("com.bling.dab.mapper")
public class DabApplication { public static void main(String[] args) {
SpringApplication.run(DabApplication.class, args);
System.out.println("dab启动完成--------OK!");
} }

多数据源jpa和mybatis 配置

jpa需要比mybatis多自定义一个配置类JpaEntityManager,其中的俩个bean需要在这里依赖,这个注解也可以写在JpaEntityManager配置类上,我写在启动类上了效果一样

@EnableJpaRepositories(basePackages = { "com.bling.dab.dao" }, entityManagerFactoryRef = "entityManagerFactoryPrimary", transactionManagerRef = "transactionManagerPrimary")
/**
* @author: hxp
* @date: 2019/6/18 10:54
* @description:
*/
@Configuration
@EnableConfigurationProperties(JpaProperties.class)
@AutoConfigureAfter(DataSourceConfig.class)
public class JpaEntityManager { @Autowired
private JpaProperties jpaProperties; @Autowired
private DataSource myRoutingDataSource; @Bean(name = "entityManagerFactoryBean")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
Map<String, String> properties = jpaProperties.getProperties();
//要设置这个属性,实现 CamelCase -> UnderScore 的转换
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"); return builder
.dataSource(myRoutingDataSource)
.properties(properties)
.packages("com.bling.dab.domain")
.persistenceUnit("myPersistenceUnit")
.build();
} @Primary
@Bean(name = "entityManagerFactoryPrimary")
public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder) {
return this.entityManagerFactoryBean(builder).getObject();
} @Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder));
} }

然后是mybati和jpa都需要的数据源配置

@Configuration
public class DataSourceConfig { @Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "slave1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave1")
public DataSource slave1DataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "slave2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave2")
public DataSource slave2DataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "myRoutingDataSource")
public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slave1DataSource") DataSource slave1DataSource,
@Qualifier("slave2DataSource") DataSource slave2DataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);
targetDataSources.put(DBTypeEnum.SLAVE1, slave1DataSource);
targetDataSources.put(DBTypeEnum.SLAVE2, slave2DataSource);
MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();
myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
myRoutingDataSource.setTargetDataSources(targetDataSources);
return myRoutingDataSource;
} }

轮询数据源使用的类DBContextHolder

public class DBContextHolder {

    private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();

    private static final AtomicInteger counter = new AtomicInteger(-1);

    public static void set(DBTypeEnum dbType) {
contextHolder.set(dbType);
} public static DBTypeEnum get() {
return contextHolder.get();
} public static void master() {
set(DBTypeEnum.MASTER);
System.out.println("切换到master");
} public static void slave() {
// 轮询
int index = counter.getAndIncrement() % 2;
if (counter.get() > 9999) {
counter.set(-1);
}
if (index == 0) {
set(DBTypeEnum.SLAVE1);
System.out.println("切换到slave1");
}else {
set(DBTypeEnum.SLAVE2);
System.out.println("切换到slave2");
}
}
}

单独定义的MyRoutingDataSource,使用的是spring提供的路由方法,因为多个地方使用,所以单独定义的

public class MyRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.get();
}
}

mybatis需要的配置类MyBatisConfig

@EnableTransactionManagement
@Configuration
public class MyBatisConfig { @Resource(name = "myRoutingDataSource")
private DataSource myRoutingDataSource; @Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(myRoutingDataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
} @Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(myRoutingDataSource);
}

切面类实现方法级别的读写分离

@Aspect
@Component
public class DataSourceAspect { @Pointcut("!@annotation(com.bling.dab.common.annotation.Master) " +
"&& (execution(* com.bling.dab.service..*.select*(..)) " +
"|| execution(* com.bling.dab.service..*.get*(..)))"+
"|| execution(* com.bling.dab.service..*.find*(..)))"+
"|| execution(* com.bling.dab.service..*.query*(..)))")
public void readPointcut() { } @Pointcut("@annotation(com.bling.dab.common.annotation.Master) " +
"|| execution(* com.bling.dab.service..*.insert*(..)) " +
"|| execution(* com.bling.dab.service..*.add*(..)) " +
"|| execution(* com.bling.dab.service..*.save*(..)) " +
"|| execution(* com.bling.dab.service..*.update*(..)) " +
"|| execution(* com.bling.dab.service..*.edit*(..)) " +
"|| execution(* com.bling.dab.service..*.delete*(..)) " +
"|| execution(* com.bling.dab.service..*.remove*(..))")
public void writePointcut() { } @Before("readPointcut()")
public void read() {
DBContextHolder.slave();
} @Before("writePointcut()")
public void write() {
DBContextHolder.master();
}
}

注解配合切面类使用

 * @description:该注解标注的就读主库
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Master { }

枚举一个

public enum DBTypeEnum {

    MASTER, SLAVE1, SLAVE2;
}

mysql数据库配置

MySQL用的是本地的只有一台服务器,所以需要配置三个MySQL服务器,原来只有一个,现在改一下新安装了三个mysql服务器MySQLMaster、MySQLSlave1、MySQLSlave2用来测试读写分离,原来的MySQL服务不动

首先cmd进入到MySQL命令窗口

1.打开【开始】》【运行】输入【cmd】单击【确定】后出现CMD命令黑色窗口,这就是我们说的CMD命令行,或者使用快捷键Windows键(在键盘上有个Windows标志的按键)+R输入cmd后回车。

2.在CMD命令窗口敲入命令 mysql -hlocalhost -uroot -p

后按回车(注意这里的"-h"、"-u"、"-p"不能省略) 进入mysql数据库,其中"-h"表示服务器名,localhost表示本地;"-u"为数据库用户名,root是MySQL默认用户名;"-p"为密码,如果设置了密码,可直接在-p后链接输入,如:-p888888,用户没有设置密码,显示Enter password时,直接回车即可。

注意如果您的MySQL没有安装在C盘下,先使用DOS命令进入MySQL的安装目录下的bin目录中。方法如下:输入G:进入G盘),在输入cd G:\phpstudy\mysql\bin 进入到MySQL的bin目录下,才可以输入 mysql -hlocalhost -uroot -p 然后按回车键。

查看mysql版本并进入mysql命令窗口,现在只有一个mysql,配置了环境变量所以在c目录下也能找到,先查看一下原来的MySQL服务版本,后面开始配置新的主从数据库用来实现读写分离库

查看mysql的安装路径

原有的MySQL-5.7.24-winx64拷贝三份到新建的目录mysql下

结构如图

修改配置文件my.ini,拷贝的mysql中有个文件aotu.cnf记录的MySQL的uuid需要改一下,不能相同

master

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
#设置3306端口
port = 3307
# 设置mysql的安装目录 这里可以修改
basedir=D:\hxpinstall\mysql\mysql-master
# 设置mysql数据库的数据的存放目录,这里可以修改
datadir=D:\hxpinstall\mysql\mysql-master\mydata
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB #给数据库服务的唯一标识,一般为大家设置服务器Ip的末尾号,在一个集群中,这个id是不能重复的
server-id=1
#开启二进制文件;后面设置的这个master-bin就是二进制文件的名字前缀(名字)
log-bin=master-bin
#开启二进制文件的索引;名字一般为log-bin.index
log-bin-index=master-bin.index
[client]
#设置mysql客户端连接服务端时默认使用的端口
port = 3307
default-character-set=utf8

slave1

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
#设置3306端口
port = 3308
# 设置mysql的安装目录 这里可以修改
basedir=D:\hxpinstall\mysql\mysql-slave1
# 设置mysql数据库的数据的存放目录,这里可以修改
datadir=D:\hxpinstall\mysql\mysql-slave1\mydata
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB server-id=2
relay-log=slave-relay-bin
relay-log-index=slave-relay-bin.index [client]
#设置mysql客户端连接服务端时默认使用的端口
port = 3308
default-character-set=utf8

slave2

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
#设置3306端口
port = 3309
# 设置mysql的安装目录 这里可以修改
basedir=D:\hxpinstall\mysql\mysql-slave2
# 设置mysql数据库的数据的存放目录,这里可以修改
datadir=D:\hxpinstall\mysql\mysql-slave2\mydata
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB server-id=3
relay-log=slave-relay-bin
relay-log-index=slave-relay-bin.index [client]
#设置mysql客户端连接服务端时默认使用的端口
port = 3309
default-character-set=utf8

原来的MySQL服务不停,启动新的这三个数据库分别

测试读写分离的时候用的库,端口号为3307、3308、3309,记得配置环境变量

启动服务试试看,分别到安装bin目录下,以管理员身份cmd

执行net start mysql

查看服务启动情况

先停掉原来的MySQL服务windows+R

配置mysqlmaster服务时没有指定启动的mysql路径,产生一个多余的服务可以执行命令清除,以下为清除多余的服务并重新启动的过程

给用户配置主从复制的权限:

mysql> grant replication slave on *.* to 'root'@'%' identified by 'root';
Query OK, 0 rows affected, 1 warning (0.01 sec)

注:

@后面的ip地址为允许连接的客户端的ip地址,如果改为 ‘%’,就表示客户端没有ip地址的限制
然后查看主服务master的状态: (每重启一次mysql服务,mysql-bin的日志就会新建一个,所以重启主服务,从服务必须先停止再重新配置后启动)
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000004 | 437 | dab | mysql | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

注:

请记住这个File和Position,File是同步给从库的数据库文件,到时候授权给从库时要用

navicat连接mysqlmaster成功!

mydata下的*.err文件

mysqlslave1和2依次安装启动

图片太费劲,代码放这里

D:\hxpinstall\mysql\mysql-slave1\bin>mysqld --initialize

D:\hxpinstall\mysql\mysql-slave1\bin>
D:\hxpinstall\mysql\mysql-slave1\bin>mysqld --install MySQLSlave1 --defaults-file=D:\hxpinstall\mysql\mysql-slave1\my.ini
Service successfully installed. D:\hxpinstall\mysql\mysql-slave1\bin>net start MySQLSlave1
MySQLSlave1 服务正在启动 .
MySQLSlave1 服务已经启动成功。 D:\hxpinstall\mysql\mysql-slave1\bin>mysql -u root -p
Enter password: ************
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.24 Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> ALTER user 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0.00 sec) mysql> exit;
Bye D:\hxpinstall\mysql\mysql-slave1\bin>cd ../../ D:\hxpinstall\mysql>cd mysql-slave2\bin D:\hxpinstall\mysql\mysql-slave2\bin>mysqld --initialize D:\hxpinstall\mysql\mysql-slave2\bin>mysqld --install MySQLSlave2 --defaults-file=D:\hxpinstall\mysql\mysql-slave2\my.ini
Service successfully installed. D:\hxpinstall\mysql\mysql-slave2\bin>net start MySQLSlave2
MySQLSlave2 服务正在启动 .
MySQLSlave2 服务已经启动成功。
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000005 | 154 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec) mysql> exit
Bye

主从数据库启动成功后,分别执行show master status;和show slave status\G;查看主从数据库状态。此时主库(master)下生成了一个二进制的日志文件,而slave下是空的,所以就要把主库与从库关联起来,即只需要让从库(slave)知道主库(master)的地址就可以了。在从库(slave)执行如下命令,将主库与从库联系起来,然后执行命令start slave开启主从同步。

change master to master_host='localhost',master_port=3306,master_user='root',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=120;

开启复制

start slave

停止复制

stop slave

mysql> show slave status\G;
Empty set (0.00 sec) ERROR:
No query specified

执行指定主库命令

mysql> change master to master_host='localhost',master_port=3307,master_user='root',master_password='root',master_log_file='mysql-bin.000005',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.06 sec)

执行开启复制

start slave

再到mysqlslave2从库下执行一次

执行开启复制

start slave

这样3台新mysql服务器安装成功并且主从数据库关联

测试一下主从关联是否成功,正在测试。。。

在从库中执行show slave status\G;

再次检查设置过程

在master库中执行刷新log命令,每次刷新,log文件加1

在进入slave库重新设置

所以重新来一次对的

执行show slave status;看看

测试建表看看

现在master库执行sql

CREATE TABLE `login_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8;

查看从库

如法在slave2设置一下,也成功建表

最后测试数据读写分离的效果

保存数据测试类

写入操作成功切换到master库

数据库数据也成功写入

查询看看

查询测试类

[10:56:00:654] [INFO] - org.springframework.boot.StartupInfoLogger.logStarted(StartupInfoLogger.java:59) - main - Started DabApplicationTests in 13.68 seconds (JVM running for 15.591)
切换到slave2
[10:56:00:793] [INFO] - com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:110) - main - HikariPool-2 - Starting...
[10:56:00:818] [INFO] - com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:123) - main - HikariPool-2 - Start completed.
[10:56:01:008] [INFO] - com.bling.dab.DabApplicationTests.selectByPrimaryKey(DabApplicationTests.java:560) - main - {"code":1,"data":{"id":1,"password":"123456","username":"张大大"},"message":"成功","success":true}

查询成功

OK结束

下次在研究mycat实现读写分离!

springboot整合jpa和mybatis实现主从复制的更多相关文章

  1. SpringBoot整合Redis、mybatis实战,封装RedisUtils工具类,redis缓存mybatis数据 附源码

    创建SpringBoot项目 在线创建方式 网址:https://start.spring.io/ 然后创建Controller.Mapper.Service包 SpringBoot整合Redis 引 ...

  2. SpringBoot数据访问(二) SpringBoot整合JPA

    JPA简介 Spring Data JPA是Spring Data大家族的一部分,它可以轻松实现基于JPA的存储库.该模块用于增强支持基于JPA的数据访问层,它使我们可以更加容易地构建使用数据访问技术 ...

  3. SpringBoot 整合jdbc和mybatis

    摘要 该文章主要为记录如何在SpringBoot项目中整合JDBC和MyBatis,在整合中我会使用简单的用法和测试用例,毕竟该文章目的是为了整合,而不是教大家如何去使用.希望大家多多包涵. 通用配置 ...

  4. 003 SpringBoot整合SpringMVC、Mybatis 案例

    1.不使用骨架创建一个maven工程 2.修改POM.xml文件 <?xml version="1.0" encoding="UTF-8"?> &l ...

  5. springboot整合druid、mybatis

    目的: 1.springboot配置数据库连接池druid 测试druid中url监控 2.springboot整合mybatis 测试查删案例 3.springboot整合pagehelper sp ...

  6. 【idea】Springboot整合jpa

    第一步快速搭建springboot项目:在你建立的工程下创建 Module 选择Spring initializr创建. 第二步:修改包名.项目名.web项目打成war包.在Type处选择: Mave ...

  7. springboot整合JPA(简单整理,待续---)

    整合步骤 引入依赖: <dependencies> <dependency> <groupId>org.springframework.boot</group ...

  8. SpringBoot非官方教程 | 第四篇:SpringBoot 整合JPA

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/11/springboot4-jpaJ/ 本文出自方志朋的博客 JPA全称J ...

  9. springBoot数据库jpa+对接mybatis

    1  spring Data jpa hibernate引领数据访问技术,使用orm对象关系映射来进行数据库访问,通过模型和数据库进行映射,通过操作对象实现对数据库操作,把数据库相关操作从代码中独立出 ...

随机推荐

  1. NX二次开发-UFUN创建B面UF_MODL_create_bsurf

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> //创建一个B面 ;//U方向极数 ;//V方向极数 ;//U方向规则 ;//V ...

  2. bat命令自用其(一)

    每秒钟打印ping命令结果到指定文件: @echo off set /p ip=Input the IP required to monitor: :starts echo %date% %time% ...

  3. python入门 集合(四)

    集合 集合是一个无序的不重复元素序列,可以迭代,也可以修改.集合迭代的时候元素是随机的. 集合通常用来 membership testing, 去重, 也可以用来求交集并集补集. 介绍一下如何创建集合 ...

  4. 'ddkbuild.cmd' 不是内部或外部命令,也不是可运行的程序

    转自VC错误:http://www.vcerror.com/?p=49 问题描述: 错误:'ddkbuild.cmd' 不是内部或外部命令,也不是可运行的程序 解决方法: 详细的解决方法可参考VC错误 ...

  5. 由于某些原因无法博客搬家,现在换马甲了 http://blog.csdn.net/qq_32066409

    由于位置原因无法博客搬家,现在换马甲到csdn了地址如下http://blog.csdn.net/qq_32066409

  6. java时间工具类,时间相互转换

    /* * @author XueWeiWei * @date 2019/8/26 16:22 */ package com.nps.utils; import java.text.ParseExcep ...

  7. python中的线程锁

    锁对象 原始锁是一个在锁定时不属于特定线程的同步基元组件.在Python中,它是能用的最低级的同步基元组件,由 _thread 扩展模块直接实现. 原始锁处于 "锁定" 或者 &q ...

  8. 买不到的数目 /// 结论公式 oj26316

    题目大意: 给定a b(这题题意不清 其实a b互质) 设变量x y(x>=0,y>=0),求 x*a+y*b=c 找到最大的不可能达到的c 如a=4 b=7 那么c=14 有这样一个定理 ...

  9. I Love Palindrome String HDU - 6599 回文树+hash

    题意: 输出每个长度下的回文串(这些回文串的左半边也需要是回文串) 题解: 直接套上回文树,然后每找到一个回文串就将他hash. 因为符合要求的回文串本身是回文串,左半边也是回文串,所以它左半边也右半 ...

  10. 常见PID里面的像素大小

    因为tensorflow/models里faster R-cnn目前识别的好像是按照像素比上图片大小来识别的,所以在这里统计一下各个元件的像素大小的范围 DCS:70~200