官方文档

1. ShardingSphere

1.1 ShardingSphere简介

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。

ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 它与NoSQL和NewSQL是并存而非互斥的关系。NoSQL和NewSQL作为新技术探索的前沿,放眼未来,拥抱变化,是非常值得推荐的。反之,也可以用另一种思路看待问题,放眼未来,关注不变的东西,进而抓住事物本质。 关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。

ShardingSphere目前已经进入Apache孵化器, 欢迎通过shardingsphere的dev邮件列表与我们讨论。

1.2 Sharding-JDBC简介

定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。

2. 读写分离简介

2.1 背景

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

与将数据根据分片键打散至各个数据节点的水平分片不同,读写分离则是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。

读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读写分离联合使用,能够更加有效的提升系统性能。

2.2 挑战

读写分离虽然可以提升系统的吞吐量和可用性,但同时也带来了数据不一致的问题。 这包括多个主库之间的数据一致性,以及主库与从库之间的数据一致性的问题。 并且,读写分离也带来了与数据分片同样的问题,它同样会使得应用开发和运维人员对数据库的操作和运维变得更加复杂。 下图展现了将分库分表与读写分离一同使用时,应用程序与数据库集群之间的复杂拓扑关系。

2.3 目标

透明化读写分离所带来的影响,让使用方尽量像使用一个数据库一样使用主从数据库集群,是ShardingSphere读写分离模块的主要设计目标。

2.4 核心概念

2.4.1 主库

添加、更新以及删除数据操作所使用的数据库,目前仅支持单主库

2.4.2 从库

查询数据操作所使用的数据库,可支持多从库。

2.4.3 主从同步

将主库的数据异步的同步到从库的操作。由于主从同步的异步性,从库与主库的数据会短时间内不一致。(这一步由数据库层实现,一般RDS数据库提供商,都会提供读写分离的服务)

2.4.4 负载均衡策略

通过负载均衡策略将查询请求疏导至不同从库。

2.5 核心功能

  1. 提供一主多从的读写分离配置,可独立使用,也可配合分库分表使用。
  2. 独立使用读写分离支持SQL透传。
  3. 同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。
  4. 基于Hint的强制主库路由。

2.6 不支持项

  1. 主库和从库的数据同步。
  2. 主库和从库的数据同步延迟导致的数据不一致。
  3. 主库双写或多写。

3. 读写分离Demo

3.1 添加pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tao.learn</groupId>
<artifactId>m1-7-sharding</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sharding</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>11</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- JPA --> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> <!-- postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-core -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.0.0-RC1</version>
</dependency> <!-- for spring boot -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency> <!-- for spring namespace -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.0.0-RC1</version>
</dependency> <dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>4.0.0-RC1</version>
</dependency> <!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

3.2 配置文件

Mysql读写分离, 采用Druid作为datasource

# Mysql读写分离, 采用Druid作为datasource
spring.shardingsphere.datasource.names=master,slave0,slave1 spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://localhost:3306/master?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456 spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://localhost:3306/slave0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=123456 spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.url=jdbc:mysql://localhost:3306/slave1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=123456 spring.shardingsphere.masterslave.name=ms
spring.shardingsphere.masterslave.master-data-source-name=master
spring.shardingsphere.masterslave.slave-data-source-names=slave0,slave1 spring.shardingsphere.props.sql.show=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

PostgreSQL读写分离,采用druid作为datasource

# PostgreSQL读写分离,采用druid作为datasource
spring:
shardingsphere:
datasource:
names: master,slave0,slave1
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/slave0
username: postgres
password: postgres
slave0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/slave1
username: postgres
password: postgres
slave1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/slave2
username: postgres
password: postgres
masterslave:
load-balance-algorithm-type: round_robin
name: ms
master-data-source-name: master
slave-data-source-names: slave0,slave1
props:
sql.show: true
jpa:
properties:
hibernate:
dialect=org:
hibernate:
dialect:
PostgreSQLDialect: org.hibernate.dialect.PostgreSQLDialect

PostgreSQL读写分离,采用hikari作为datasource

# PostgreSQL读写分离,采用hikari作为datasource

spring:
shardingsphere:
datasource:
names: master,slave0,slave1
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/master
username: postgres
password: postgres
slave0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/slave0
username: postgres
password: postgres
slave1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/slave1
username: postgres
password: postgres
masterslave:
load-balance-algorithm-type: round_robin
name: ms
master-data-source-name: master
slave-data-source-names: slave0,slave1
props:
sql.show: true
jpa:
properties:
hibernate:
temp:
use_jdbc_metadata_defaults: false
dialect: org.hibernate.dialect.PostgreSQLDialect

PostgreSQL采用hikari作为datasource,datasource下的url改为jdbc-url

application.yml

spring:
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
show_sql: true profiles:
active: master-slave-postgresql-hikari
main:
allow-bean-definition-overriding: true

3.3 编写CRUD基本操作

entity

/**
* @author Jiantao Yan
* @description: User实体类
* @title: UserServiceImpl
* @date 2019/12/24 15:03
*/
@Data
@Entity
@Table(name = "tb_user")
@EntityListeners(AuditingEntityListener.class)
public class User {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; /**
* 姓名
*/
private String name; /**
* 年龄
*/
private Integer age; /**
* 性别
*/
private Integer sex; /**
* 创建时间
*/
@CreatedDate
private LocalDateTime createTime; /**
* 更新时间
*/
@LastModifiedDate
private LocalDateTime updateTime;
}

dao

/**
* @author Jiantao Yan
* @description: 用户dao层
* @title: UserServiceImpl
* @date 2019/12/24 15:03
*/
@Component
public interface UserDao extends JpaRepository<User, Long> {
}

service

/**
* @author Jiantao Yan
* @description: User Service接口层
* @title: UserService
* @date 2019/12/24 15:03
*/
public interface UserService { List<User> findAll(); User save(User user); void update(User user); void delete(Long id); List<User> transaction(User user);
}
/**
* @author Jiantao Yan
* @description: User Service 实现层
* @title: UserServiceImpl
* @date 2019/12/24 15:03
*/
@Service
public class UserServiceImpl implements UserService { @Autowired
private UserDao userDao; @Override
public List<User> findAll() { return userDao.findAll();
} @Override
public User save(User user) {
return userDao.save(user);
} @Override
public void update(User user) {
userDao.save(user);
} @Override
public void delete(Long id) {
userDao.deleteById(id);
} @Override
@Transactional(rollbackFor = Exception.class)
public List<User> transaction(User user) {
userDao.deleteById(user.getId());
return userDao.findAll();
}
}

controller

/**
* @author Jiantao Yan
* @description: 用户Controller层
* @title: UserController
* @date 2019/12/24 15:13
*/
@RestController
@RequestMapping("/user")
public class UserController { @Autowired
private UserService userService; @GetMapping("/")
public List<User> findAll() {
return userService.findAll();
} @GetMapping("/transaction")
public List<User> transaction(@RequestBody User user) {
return userService.transaction(user);
} @PostMapping("/")
public User save(@RequestBody User user) {
return userService.save(user);
} @PutMapping("/")
public Object update(User user) {
userService.update(user);
Map<String, Object> result = new HashMap<>(2);
result.put("code", 200);
result.put("msg", "更新成功");
return result;
} @DeleteMapping("/{id}")
public Object save(@PathVariable(name = "id") Long id) {
userService.delete(id);
Map<String, Object> result = new HashMap<>(2);
result.put("code", 200);
result.put("msg", "更新成功");
return result;
}
}

3.4 SQL

MySql建表语句

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名字',
`age` mediumint(9) NOT NULL DEFAULT 0 COMMENT '年龄',
`sex` tinyint(4) NOT NULL DEFAULT 0 COMMENT '性别:0无,1男,2女',
`create_time` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
`update_time` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 398790076873572353 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表0' ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;

PostgreSql建表语句

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS "public"."tb_user";
CREATE TABLE "public"."tb_user" (
"id" int8 NOT NULL DEFAULT nextval('tb_user_id_seq'::regclass),
"age" int4,
"create_time" timestamp(6),
"name" varchar(255) COLLATE "pg_catalog"."default",
"sex" int4,
"update_time" timestamp(6)
)
; -- ----------------------------
-- Primary Key structure for table tb_user
-- ----------------------------
ALTER TABLE "public"."tb_user" ADD CONSTRAINT "tb_user_pkey" PRIMARY KEY ("id");

3.5 测试

3.5.1 插入操作

使用主库进行插入操作

2020-01-03 10:33:34.532  INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Rule Type: master-slave
2020-01-03 10:33:34.532 INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL : SQL: insert into tb_user (age, create_time, name, sex, update_time) values (?, ?, ?, ?, ?) ::: DataSources: master
Hibernate: select currval('tb_user_id_seq')
2020-01-03 10:33:34.545 INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:33:34.546 INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL : SQL: select currval('tb_user_id_seq') ::: DataSources: master

3.5.2 查询操作

使用从库查询,并且两个从库进行轮询

2020-01-03 10:33:34.545  INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Rule Type: master-slave
2020-01-03 10:33:34.546 INFO 2584 --- [nio-8080-exec-2] ShardingSphere-SQL : SQL: select currval('tb_user_id_seq') ::: DataSources: master
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_
2020-01-03 10:36:23.344 INFO 2584 --- [nio-8080-exec-5] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:36:23.345 INFO 2584 --- [nio-8080-exec-5] ShardingSphere-SQL : SQL: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_ ::: DataSources: slave1
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_
2020-01-03 10:36:57.317 INFO 2584 --- [nio-8080-exec-6] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:36:57.317 INFO 2584 --- [nio-8080-exec-6] ShardingSphere-SQL : SQL: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_ ::: DataSources: slave0

3.5.3 事务操作

该线程只要有一个是增删改,则该线程的后续操作全部采用主库master

Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.create_time as create_t3_0_0_, user0_.name as name4_0_0_, user0_.sex as sex5_0_0_, user0_.update_time as update_t6_0_0_ from tb_user user0_ where user0_.id=?
2020-01-03 10:39:20.562 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:39:20.563 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : SQL: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.create_time as create_t3_0_0_, user0_.name as name4_0_0_, user0_.sex as sex5_0_0_, user0_.update_time as update_t6_0_0_ from tb_user user0_ where user0_.id=? ::: DataSources: slave1
Hibernate: delete from tb_user where id=?
2020-01-03 10:39:20.565 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:39:20.565 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : SQL: delete from tb_user where id=? ::: DataSources: master
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_
2020-01-03 10:39:20.567 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : Rule Type: master-slave
2020-01-03 10:39:20.567 INFO 2584 --- [nio-8080-exec-3] ShardingSphere-SQL : SQL: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.create_time as create_t3_0_, user0_.name as name4_0_, user0_.sex as sex5_0_, user0_.update_time as update_t6_0_ from tb_user user0_ ::: DataSources: master

全部使用主库的前提的要有一个增删改操作,后续才使用主库,而不是所有的事务操作都会使用主库

例如:

  1. 查->改->删->查

    该操作所对应的数据库为:从->主->主->主

  2. 改->查->删->增->查

    该操作所对应的数据库为:主->主->主->主->主

4. 结语

采用sharding-jdbc做读写分离的好处有以下几点:

  • 对项目代码零侵入,不用修改业务层的代码
  • 从库可设置路由策略
  • 可独立使用,也可配合以后分库分表作为使用
  • 同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性

缺点:

  • 主库读写策略不是根据事务来划分,而是根据同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性
  • 主从库数据不支持(不影响)
  • 主库双写或多写(不影响)

源码位置:learn

shading-jdbc数据库读写分离的更多相关文章

  1. Spring aop应用之实现数据库读写分离

    Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...

  2. [转]Spring数据库读写分离

    数据库的读写分离简单的说是把对数据库的读和写操作分开对应不同的数据库服务器,这样能有效地减轻数据库压力,也能减轻io压力. 主(master)数据库提供写操作,从(slave)数据库提供读操作,其实在 ...

  3. java环境下的数据库读写分离

    方案很多:阿里的中间件cobar.aop注解方式.com.mysql.jdbc.ReplicationDriver读写分离驱动MySQL数据库的同步. MySQL是开源的关系型数据库系统.主从同步复制 ...

  4. spring+mybatis利用interceptor(plugin)兑现数据库读写分离

    使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是"地位相当"的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这 ...

  5. 学会数据库读写分离、分表分库——用Mycat,这一篇就够了!

    系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...

  6. 学会数据库读写分离、分表分库——用Mycat

    系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...

  7. Spring + Mybatis项目实现数据库读写分离

    主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...

  8. Spring+MyBatis实现数据库读写分离方案

    推荐第四种:https://github.com/shawntime/shawn-rwdb 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactor ...

  9. (转)学会数据库读写分离、分表分库——用Mycat,这一篇就够了!

    原文:https://www.cnblogs.com/joylee/p/7513038.html 系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理 ...

  10. 在应用层通过spring特性解决数据库读写分离

    如何配置mysql数据库的主从? 单机配置mysql主从:http://my.oschina.net/god/blog/496 常见的解决数据库读写分离有两种方案 1.应用层 http://neore ...

随机推荐

  1. C# 文件系统

    检查驱动器信息 DriveInfo[] drives = DriveInfo.GetDrives(); foreach(var drive in drives) { if (drive.IsReady ...

  2. Ubuntu Vmware虚拟机 没有共享文件夹/mnt/hgfs 解决

    问题现象 在Vmware虚拟机设置共享文件夹后,在Ubuntu系统侧应该在/mnt/hgfs目录下可见.然而,有时在重启虚拟机后不存在该文件夹. 解决方法 在终端中执行以下代码,需要root权限. s ...

  3. K8s新手系列之指定Pod调度到指定节点上

    概述 在 Kubernetes 中,Pod的调度是通过kube-schedule来实现的,Pod的调度会经过一系列算法来进行完成. 在实际生产过程中,我们想让Pod调度到我们想要的节点上,往往通过ku ...

  4. MVVM - Model和ViewModel的创建和配置

    MVVM-Model和ViewModel的创建和配置 本文同时为b站WPF课程的笔记,相关示例代码 简介 MVVM:Model-View-ViewModel,是一种软件架构的模式.通过引入一个中间层V ...

  5. [Python] 开发一个lychee相册命令行客户端以及python库pychee6

    有一段时间收集了不少的写真集和漫画,但是一直苦于没有很好的组织和储存的方法,直到我找到了LycheeOrg/Lychee ,它的图片组织形式非常适合存放写真集或者漫画,于是我尝试把图片都放上去.体验很 ...

  6. const关键字和指针

    const指针 const关键字 1.const int p const int p 与 int const p 是等价的. 用const修饰变量 p 时,则 p 成为只读变量,必须在定义的同时初始化 ...

  7. luffy

    Luffy 本项目使用Vue+Vite+Django+DRF+Elementui-Plus编写 项目需求介绍 # 线上销售课程的 -商城 -知识付费类 # 需求 -首页功能 -轮播图接口 -推荐课程接 ...

  8. ATM2.0模块版

    ATM项目开发 (1)在主程序文件中创建程序入口 (2)在核心代码文件(视图层)搭建程序框架 (3)进行代码功能分配 - ATM 项目根目录 - README.md 项目说明书 - start.py ...

  9. 使用acme.sh颁发TLS证书并安装到nginx/apache实现网站https访问

    原文永久链接:https://forum.piwind.com/d/22-shi-yong-acmeshban-fa-tlszheng-shu-bing-an-zhuang-dao-nginxapac ...

  10. dotnet (.Net) Core在不是Web 项目中使用HttpClientFactory正确用法

    在不是web 项目中也不是Api 中使用 HttpClientFactory 先需要添加 Microsoft.Extensions.DependencyInjection.Abstractions M ...