目录
前言:
平时开发中,可能会遇见数据量越来越大的情况,一般数据量过千万级别,就必须考虑分库分表的情况了,来减少io 服务器压力, 这里目前记录一下 水平分库的demo
讲解:
- 水平分库是指将一个数据库中的数据按照某种规则分散到多个数据库中,以达到分散负载、提高性能的目的。在MySQL中,可以通过分表和分库两种方式来实现水平分库。
- 分表是指将一个大表按照某种规则拆分成多个小表,每个小表存储一部分数据。例如,可以按照时间、地区、用户等维度来拆分表。分表的优点是可以减少单个表的数据量,提高查询性能。缺点是需要在应用程序中处理多个表的查询和更新操作,增加了开发和维护的难度。
- 分库是指将一个数据库中的数据按照某种规则拆分成多个数据库,每个数据库存储一部分数据。例如,可以按照用户ID、地区等维度来拆分数据库。分库的优点是可以将数据分散到多个物理服务器上,提高并发处理能力和可用性。缺点是需要在应用程序中处理多个数据库的查询和更新操作,增加了开发和维护的难度。
第一种方式的水平分库:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MySQLSharding {
private static final String URL_PREFIX = "jdbc:mysql://";
private static final String URL_SUFFIX = "?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "password";
public Connection getConnection(int userId) throws SQLException {
String url = URL_PREFIX + getDatabaseName(userId) + URL_SUFFIX;
return DriverManager.getConnection(url, USERNAME, PASSWORD);
}
private String getDatabaseName(int userId) {
int databaseIndex = userId % 2;
return "database_" + databaseIndex;
}
}
示例中,我们创建了一个MySQLSharding类,并定义了一个getConnection方法。getConnection方法用于获取一个数据库连接,根据用户ID来选择连接的数据库。我们使用getDatabaseName方法根据用户ID计算出要连接的数据库名,例如"database_0"或"database_1"。然后,我们使用JDBC连接MySQL数据库,并返回一个Connection对象。
注意 分库后需要考虑数据一致性和事务处理等问题:
如果一个事务中的多个操作需要涉及到多个数据库,那么需要使用分布式事务来保证事务的一致性。常见的分布式事务解决方案包括XA协议、TCC事务、SAGA事务等。
例如,如果一个表被拆分到多个数据库中,那么在进行查询时需要将多个数据库中的数据进行合并。如果一个表的数据被拆分到多个表中,那么在进行查询时需要将多个表中的数据进行合并。这些操作需要在应用程序中进行处理
Mysql水平分库数据查询合并:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class QueryService {
private MySQLSharding mySQLSharding;
public QueryService(MySQLSharding mySQLSharding) {
this.mySQLSharding = mySQLSharding;
}
public List<User> queryUsersByRegion(String region) throws SQLException {
List<User> users = new ArrayList<>();
for (int i = 0; i < 2; i++) {
try (Connection connection = mySQLSharding.getConnection(i)) {
String sql = "SELECT * FROM user WHERE region = ?";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, region);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setRegion(resultSet.getString("region"));
users.add(user);
}
}
}
}
}
return users;
}
}
我们创建了一个QueryService类,并定义了一个queryUsersByRegion方法。queryUsersByRegion方法用于查询指定地区的用户信息。我们使用MySQLSharding类来获取数据库连接,根据用户ID来选择连接的数据库。然后,我们在每个数据库中执行查询操作,并将查询结果合并到一个List中。
代码讲解:
- 这个示例中,我们使用
statement.setString(1, region)
将第一个参数的值设置为region
,这样就可以根据指定的地区查询用户信息了。mySQLSharding.getConnection(i)
是获取第i
个数据库的连接。在这个示例中,我们使用了一个MySQLSharding
对象来管理多个数据库的连接。getConnection(i)
方法根据用户ID计算出要连接的数据库名,例如 "database_0" 或 "database_1",然后使用 JDBC 连接 MySQL 数据库,并返回一个Connection
对象。
MySQL水平分库插入数据:
public void insertUser(User user) throws SQLException {
try (Connection connection = mySQLSharding.getConnection(user.getId())) {
String sql = "INSERT INTO user (id, name, region) VALUES (?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, user.getId());
statement.setString(2, user.getName());
statement.setString(3, user.getRegion());
statement.executeUpdate();
}
}
}
定义了一个insertUser方法。insertUser方法用于向数据库中插入一条用户信息。我们使用MySQLSharding类来获取数据库连接,根据用户ID来选择连接的数据库。然后,我们在指定的数据库中执行插入操作。