MyBatis 数据处理:主键获取、批量删除与动态表名
1.主键获取
XML配置中使用了useGeneratedKeys="true"和keyProperty="id"来自动获取并设置插入后的自增主键。这是一个标准的做法。
1)mapper接口
/*** 添加数据时获取自增id*/
int addUserGetId(User user);
2)mapper.xml
<!--添加数据时获取自增主键--> <insert id="addUserGetId" parameterType="org.xiji.enty.User" useGeneratedKeys="true" keyProperty="id">insert into user (username,password,userInfo) values(#{username},#{password},#{userInfo}) </insert>
3)测试代码
在测试代码中,user.getId()
应该能够返回插入后数据库自动生成的主键值。注意,这需要数据库支持自增主键,并且在JDBC连接中正确配置了自动生成主键的功能。
/*** 获取添加数据时的主键*/ @Test public void testAddUserGetId() {User user = new User();user.setUsername("test");user.setPassword("123456");user.setUserInfo("test");int id = specialMapper.addUserGetId(user);System.out.println("插入时,主键回显到传入的参数中"+user.getId()); }
4)测试结果
2.批量删除
使用${ids}直接拼接SQL语句的方式存在SQL注入的风险,不建议使用。而使用<foreach>标签则是更安全的方式。
1)mapper接口
1-使用手动拼接字符串数组的方法
/*** 批量删除*/
int deleteBatch(String ids);
2-使用mybatis中的foreach标签
/*** 通过传入的数组*/
int deleteUserByArray(@Param("array") int[] array);
2)mapper.xml
1-使用手动拼接字符串数组的方法
<!--这种是手动拼接 批量删除获取参数-->
<delete id="deleteBatch" >delete from user where id in (${ids})
</delete>
2-使用mybatis中的foreach标签
<!--通过传入的数组--> <!--批量删除获取参数--> <delete id="deleteUserByArray" >delete from user where id in <foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach> </delete>
3)测试代码
对于使用<foreach>标签的方法,测试代码看起来是正确的。注意,@Param("array") int[] array这样的参数传递方式是正确的,MyBatis会识别数组并正确地将其传递给SQL语句。
1-使用手动拼接字符串数组的方法
/*** 批量删除的特殊处理*/ @Test public void testDeleteBatch() { // 手动把输入传入的集合转化为字符串,传入int result = specialMapper.deleteBatch("4,5,6");System.out.println(result); }
2-使用mybatis中的foreach标签
/*** 通过传入数组批量删除*/ @Test public void testAddUserByArray() {int[] array = {2,7};int result = specialMapper.deleteUserByArray(array);System.out.println(result); }
4)测试结果
1-使用手动拼接字符串数组的方法
2-使用mybatis中的foreach标签
这里删除第二条和第一条数据
3.动态设置表名
动态设置表名时,使用${tableName}可以直接将变量值嵌入到SQL语句中,但这同样存在SQL注入的风险。如果tableName是从外部输入获得的话,请务必进行严格的验证和过滤。
1)mapper接口
/*** 动态设置表名*/ @MapKey("id") List<Map<String,Object>> getUserByTableName(String tableName);
2)mapper.xml
/*** 动态设置表名*/ @MapKey("id") List<Map<String,Object>> getUserByTableName(String tableName);
3)测试代码
在测试代码中,动态设置表名的功能得到了验证,但是要注意在实际应用中确保表名的安全性。
/*** 动态获取设置表名*/ @Test public void testGetUserByTableName(){System.out.println("查询第一张表");List<Map<String, Object>> user = specialMapper.getUserByTableName("user");for (int i = 0; i < user.size(); i++) {System.out.println(user.get(i).toString());}System.out.println(user);System.out.println("======================================================");System.out.println("查询第二张表");List<Map<String, Object>> user2 = specialMapper.getUserByTableName("user2");for (int i = 0; i < user2.size(); i++) {System.out.println(user2.get(i).toString());}System.out.println(user2);}
4)测试结果
user表的数据
user2表内容
5)扩展(水平分表的查询实现)
对于水平分表的情况,需要根据ID来决定查询哪个表。在这个例子中,queryUserByTableName方法接收两个参数:id和tableName。然后根据id的值来决定查询哪个表。这种方式在处理分表的情况下是有效的,但同样要注意表名的安全性。
例:现在我们有一张表数据量太多了,想要垂直分表
下面是思路
user表有6条数据
我们想要从3号id开始垂直分,分到user2表中
1-mapper接口
/*** 水平分表*/
List<User> queryUserByTableName(@Param("id") int id,@Param("tableName") String tableName);
2-mapper.xml
<!--水平分表查询--> <select id="queryUserByTableName" resultType="org.xiji.enty.User" >select * from ${tableName} where id=#{id}</select>
3-test代码
@Test public void testQueryUserByTableName2() {//用于接受数据List<User> userList =null;int id = 2;/*** 随机查询*/for (int i = 0; i < 6; i++) {id = (int) (Math.random()*6);/*如果id等于零那就赋值唯1*/if (id == 0) {id = 1;}System.out.println("======================================================");System.out.println("请输入要查询的id"); //传入查询idif (id < 4 && id > 0) {userList = specialMapper.queryUserByTableName(id, "user");}if (id > 3 && id < 7) {userList=specialMapper.queryUserByTableName(id,"user2");}for (int j = 0; j < userList.size(); j++) {User user = userList.get(j);System.out.println(user.toString());}}}
4-测试结果
附录:
1 SpecialMapper文件
package org.xiji.mapper;import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xiji.enty.User;import java.util.List;
import java.util.Map;@Mapper
public interface SpecialMapper {/*** 批量删除*/int deleteBatch(@Param("ids") String ids);/*** 动态设置表名*/@MapKey("id")List<Map<String,Object>> getUserByTableName(@Param("tableName") String tableName);/*** 添加数据时获取自增id*/int addUserGetId(User user);/*** 通过传入的数组*/int deleteUserByArray(@Param("array") int[] array);/*** 水平分表*/List<User> queryUserByTableName(@Param("id") int id,@Param("tableName") String tableName);
}
2 SpecialMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.xiji.mapper.SpecialMapper"><!--添加数据时获取自增主键--><insert id="addUserGetId" parameterType="org.xiji.enty.User" useGeneratedKeys="true" keyProperty="id">insert into user (username,password,userInfo) values(#{username},#{password},#{userInfo})</insert><insert id="addUserByArray"></insert><!--通过传入的数组--><!--批量删除获取参数--><delete id="deleteUserByArray" >delete from user where id in<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach></delete><!--动态设置表名--><select id="getUserByTableName" resultType="java.util.Map">select * from ${tableName}</select><!--水平分表查询--><select id="queryUserByTableName" resultType="org.xiji.enty.User" >select * from ${tableName} where id=#{id}</select></mapper>
3.SpecialMaperTest文件
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.xiji.enty.User;
import org.xiji.mapper.SpecialMapper;import java.util.List;
import java.util.Map;
import java.util.Scanner;@SpringJUnitConfig(locations = {"classpath:springConfig.xml"})
public class SpecialMapperTest {@Autowiredprivate SpecialMapper specialMapper;/*** 获取添加数据时的主键*/@Testpublic void testAddUserGetId(){User user = new User();user.setUsername("test");user.setPassword("123456");user.setUserInfo("test");int id = specialMapper.addUserGetId(user);System.out.println("插入时,主键回显到传入的参数中"+user.getId());}/*** 批量删除的特殊处理*/@Testpublic void testDeleteBatch(){int result = specialMapper.deleteBatch("4,5,6");System.out.println(result);}/*** 动态获取设置表名*/@Testpublic void testGetUserByTableName(){System.out.println("查询第一张表");List<Map<String, Object>> user = specialMapper.getUserByTableName("user");for (int i = 0; i < user.size(); i++) {System.out.println(user.get(i).toString());}System.out.println(user);System.out.println("======================================================");System.out.println("查询第二张表");List<Map<String, Object>> user2 = specialMapper.getUserByTableName("user2");for (int i = 0; i < user2.size(); i++) {System.out.println(user2.get(i).toString());}System.out.println(user2);}/*** 通过传入数组批量删除*/@Testpublic void testAddUserByArray(){int[] array = {2,7};int result = specialMapper.deleteUserByArray(array);System.out.println(result);}/*** 水平分表查询*/@Testpublic void testQueryUserByTableName(){/*** 模拟查询*///传入查询idint id = 2;List<User> user = specialMapper.queryUserByTableName(id, "user");User user1 = user.get(0);String username = user1.getUsername();System.out.println(username);System.out.println("======================================================");id = 5;List<User> user2 = specialMapper.queryUserByTableName(id, "user2");User user3 = user2.get(0);String username2 = user3.getUsername();System.out.println(username2);}@Testpublic void testQueryUserByTableName2(){//用于接受数据List<User> userList =null;int id = 2;/*** 随机查询*/for (int i = 0; i < 6; i++) {id = (int) (Math.random()*6);/*如果id等于零那就赋值唯1*/if (id == 0) {id = 1;}System.out.println("======================================================");System.out.println("请输入要查询的id");//传入查询idif (id < 4 && id > 0) {userList = specialMapper.queryUserByTableName(id, "user");}if (id > 3 && id < 7) {userList=specialMapper.queryUserByTableName(id,"user2");}for (int j = 0; j < userList.size(); j++) {User user = userList.get(j);System.out.println(user.toString());}}}}
4.user表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名字',`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户密码',`userInfo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户信息',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;