Linux上搭建基於SpringBoot利用MyCat實現對MySQL的讀寫分離

前言

首先爲什麼要做讀寫分離呢,大多數項目都是讀的操作的次數遠遠要比寫操作的次數多,所以讓MySQL的主服務器做寫操作,從服務器做讀操作,下面詳細的說一下如何利用MyCat做讀寫分離,至於MySQL的安裝和搭建MySQL的主從複製請看我另一篇博客 Linux上MySQL安裝和搭建MySQL的主從複製和讀寫分離

MyCat的安裝及啓動

環境裝備

虛擬機:192.168.50.152(MyCat)
虛擬機:192.168.50.150(MySQl主)
虛擬機:192.168.50.151(MySQl從)

  1. 我們從網上下載一個MyCat的壓縮包,放到了/usr/local這個路徑,並解壓,解壓完之後有一個mycat的文件夾

在這裏插入圖片描述

  1. 我們進入mycat的這個文件夾,編輯conf文件夾下的schema.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- mycat_testdb是mycat的邏輯庫名稱 -->
    <schema name="mycat_testdb" checkSQLschema="true" sqlMaxLimit="100" >
	</schema>
	
        <!-- database 是MySQL數據庫的庫名 -->
    <dataNode name="dn1" dataHost="localhost1" database="test" />
 
    <dataHost name="localhost1" 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.50.150:3306" user="root" password="root">
            <!-- 可以配置多個從庫 -->
            <readHost host="hostS2" url="192.168.50.151:3306" user="root" password="root" />
        </writeHost>
    </dataHost>
</mycat:schema>
  1. 啓動MyCat,進入MyCat下的bin目錄,執行如下命令
./mycat start
  1. 查看是否啓動成功,查看MyCat下的logs文件夾下的wrapper.log,看到successfully就算啓動成功

在這裏插入圖片描述

配置SpringBoot項目
  1. 新建yml文件,配置讀和寫的JDBC連接
spring:
  datasource:
    ###可讀數據源
    select:
      jdbc-url: jdbc:mysql://192.168.50.152:8066/mycat_testdb
      driver-class-name: com.mysql.jdbc.Driver
      username: user
      password: user
    ####可寫數據源
    update:
      jdbc-url: jdbc:mysql://192.168.50.152:8066/mycat_testdb
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
  1. 三個配置文件
@Configuration
public class DataSourceConfig {

	// 創建可讀數據源
	@Bean(name = "selectDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中對應屬性的前綴
	public DataSource dataSource1() {
		return DataSourceBuilder.create().build();
	}

	// 創建可寫數據源
	@Bean(name = "updateDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中對應屬性的前綴
	public DataSource dataSource2() {
		return DataSourceBuilder.create().build();
	}

}
@Component
@Lazy(false)
public class DataSourceContextHolder {
	// 採用ThreadLocal 保存本地多數據源
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

	// 設置數據源類型
	public static void setDbType(String dbType) {
		contextHolder.set(dbType);
	}

	public static String getDbType() {
		return contextHolder.get();
	}

	public static void clearDbType() {
		contextHolder.remove();
	}

}

@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
	@Autowired
	@Qualifier("selectDataSource")
	private DataSource selectDataSource;

	@Autowired
	@Qualifier("updateDataSource")
	private DataSource updateDataSource;

	/**
	 * 這個是主要的方法,返回的是生效的數據源名稱
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
		return DataSourceContextHolder.getDbType();
	}

	/**
	 * 配置數據源信息
	 */
	@Override
	public void afterPropertiesSet() {
		Map<Object, Object> map = new HashMap<>();
		map.put("selectDataSource", selectDataSource);
		map.put("updateDataSource", updateDataSource);
		setTargetDataSources(map);
		setDefaultTargetDataSource(updateDataSource);
		super.afterPropertiesSet();
	}
}
  1. 配置aop
// 使用AOP動態切換不同的數據源
@Aspect
@Component
@Lazy(false)
@Order(0) // Order設定AOP執行順序 使之在數據庫事務上先執行
public class SwitchDataSourceAOP {
	// 這裏切到你的方法目錄
	@Before("execution(* com.example.demo.service.*.*(..))")
	public void process(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
				|| methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
			DataSourceContextHolder.setDbType("selectDataSource");
		} else {
			// 切換dataSource
			DataSourceContextHolder.setDbType("updateDataSource");
		}
	}
}
  1. controller、entity、mapper、service的編寫

@RestController
public class UserController {

	@Autowired
	private UserService userService;

	@RequestMapping("/findUser")
	public List<UserEntity> findUser() {
		return userService.findUser();
	}

	@RequestMapping("/insertUser")
	public List<UserEntity> insertUser(String userName) {
		return userService.insertUser(userName);
	}

}

public class UserEntity {

	private String userName;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

}

public interface UserMapper {
	@Select("SELECT * FROM  test ")
	public List<UserEntity> findUser();

	@Select("insert into test values (#{userName}); ")
	public List<UserEntity> insertUser(@Param("userName") String userName);
}


@Service
public class UserService {
	@Autowired
	private UserMapper userMapper;

	public List<UserEntity> findUser() {
		return userMapper.findUser();
	}

	public List<UserEntity> insertUser(String userName) {
		return userMapper.insertUser(userName);
	}

}

  1. 啓動項目,進行測試
    我們插入一條userName爲123456的數據
    在這裏插入圖片描述
    IDEA控制檯打出來的日誌爲updateDataSource數據源在這裏插入圖片描述

然後我們查詢一下剛纔插入的數據
在這裏插入圖片描述

IDEA控制檯打出來的日誌爲selectDataSource數據源
在這裏插入圖片描述

  1. 至此基於SpringBootl利用MyCat實現對MySQL的讀寫分離就搭建完畢了

總結

通過這次顆粒歸倉,發現自己對這個東西還是不熟練,還是要多多學習,積累自己!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章