一、业务场景
1.1 由于数据量非常大,需要根据根据id进行分表存储,减少数据的查询压力
1.2 使用工具类对id进行计算,保证插入表的随机性
二、jdbc插入和mybatis插入
mapper中的方法
int insertUser(@Param("user") User user, @Param("tableName") String tableName);
2.1 mybatis的xml
public Result insertUser(User user) {
if (user == null || user.getId() == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
String tableName = TableRouter.routeTable(user.getId(), "user");
User userById = this.getUserById(user.getId());
if (userById != null) {
return Result.error("用户ID已存在");
}
int i = userMapper.insertUser(user, tableName);
if (i > 0) {
return Result.success("用户插入成功");
}else{
return Result.error("用户插入失败");
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.daythree.mapper.UserMapper">
<!-- 通过拦截器自动处理表名 -->
<select id="getUserById" resultType="com.example.daythree.domain.User">
SELECT * FROM ${tableName} WHERE id = #{id}
</select>
<!-- 修正:如果id是自增主键,不要在INSERT中包含id -->
<insert id="insertUser" parameterType="com.example.daythree.domain.User">
INSERT INTO ${tableName}
(id, name, email)
VALUES
(#{user.id}, #{user.name}, #{user.email})
</insert>
<!-- 方式一:通过拦截器处理表名 -->
<select id="getUserByEmail" resultType="com.example.daythree.domain.User">
SELECT * FROM ${tableName} WHERE email = #{email}
</select>
</mapper>
ps:
主要将user插入指定表中
1.xml主要有三个参数 <id ,方法><parameterType,参数类型><resultType,返回类型>
2.主要是id和resultType,对于插入返回类型不用写 int类型
3.传入的user 使用#{user.id}获取相应的信息 可参考
2.2 jdbc插入
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
public Result insertUser(User user) {
if (user == null || user.getId() == null) {
return Result.error("用户ID不能为空");
}
String tableName = TableRouter.routeTable(user.getId(), "user");
String sql = "INSERT INTO " + tableName + " (id, name, email) VALUES (?,?,?)";
try (Connection connection = DriverManager.getConnection(url, username, password);
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setLong(1, user.getId());
preparedStatement.setString(2, user.getName());
preparedStatement.setString(3, user.getEmail());
preparedStatement.executeUpdate();
}
catch (SQLException e) {
e.printStackTrace();
return Result.error("用户插入失败,请检查是否id重复");
}
return Result.success("用户插入成功");
}
通过@Value注入配置信息,然后写sql执行
三、分表工具类
package com.example.daythree.utils;
import java.util.ArrayList;
import java.util.List;
public class TableRouter {
// 表的数量
private static final int TABLE_COUNT = 2;
// 根据用户ID路由到对应的表
public static String routeTable(Long id, String baseName) {
if (id == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
int tableIndex = (int) (id % TABLE_COUNT);
return baseName + "_" + tableIndex;
}
// 获取所有用户表
public static List<String> getAllUserTables(String baseName) {
List<String> tables = new ArrayList<>(TABLE_COUNT);
for (int i = 0; i < TABLE_COUNT; i++) {
tables.add(baseName + "_" + i);
}
return tables;
}
}
四.个人总结
业务场景就是分表存储 然后查询id 确定表查;查询其他信息 融合所有表查询
有些看似简单的操作,第一做问题很多,比如这里的指定表插入;平时mp使用多了,都不太会写mybatis的xml以及想不到jdbc插入
说明一下xml
User getUserByParam(Map<String, Object> params) 这样单个参数的 直接解析使用
<select id="getUserByParam" resultType="com.example.demo.model.User">
select `user_id`,`real_name`,`nick_name`,`sex`,`phone`,`password` from bss_user
where `phone` = #{phone} and `password` = #{password}
</select>
int insertUser(@Param("user") User user, @Param("tableName") String tableName);这样多个参数的必须指定@Param 调用必须使用Param中参数获取 比如 user.name
<insert id="insertUser" parameterType="com.example.daythree.domain.User"> INSERT INTO ${tableName} (id, name, email) VALUES (#{user.id}, #{user.name}, #{user.email}) </insert>
User getUserByParam(@Param("params") Map<String, Object> params);
<select id="getUserByParam" resultType="com.example.demo.model.User">
select `user_id`,`real_name`,`nick_name`,`sex`,`phone`,`password` from bss_user
where `phone` = #{params.phone} and `password` = #{params.password}
</select>
这里的params.phone相当于获取params的键phone的值