mybatis中多条语句插入和主键返回

在Mybatis的使用中,有时候会出现需要一对多的场景,尤其是在插入的过程中,即假设存在A,B两表。A表对B表是一对多的关系,在插入数据的过程中需要先插入A表,通过A表返回的主键然后再进行B表的查询,这个时候一般有两种操作。

方法一:首先获取A表的主键,然后通过for循环进行B表的插入
方法二:使用mybatis的foreach进行多条语句的插入

在这里的话主要是记录下第二种方法,即通过mybatis的foreach来实现多条语句的插入:

建立数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> select * from clazz;
+----------+------------+
| CLAZZ_ID | CLAZZ_NAME |
+----------+------------+
| 1 | 一年级 |
+----------+------------+
1 row in set (0.00 sec)


mysql> select * from student;
+----------+--------+----------+
| CLAZZ_ID | STU_ID | STU_NAME |
+----------+--------+----------+
| 1 | 101 | a |
| 1 | 102 | b |
+----------+--------+----------+
2 rows in set (0.00 sec)

在数据库建立的两张表会发现班级表和学生表是一对多的关系,此时如果一个班级需要插入许多个学生的话,此时就要使用mybatis的foreach进行多条语句的插入了

占位符

在这里得话需要插入多条语句得时候不能使用#,而是应该使用$。在这里为什么是这个美元的符号,暂时得猜测是$解析得为静态得,也就是说mybatis会讲集合里面的值直接填充进来,类似于在ApplicationContext.xml中动态的加载jdbc.properties,需要使用$符号。
新建Dao层类:

1
2
3
public interface clazzStudent {
Integer insertToStudent(List<Map<String,Object>> map);
}

然后建立与之对应的mapper文件:

1
2
3
4
5
6
<insert id="insertToStudent" >
insert into student(CLAZZ_ID,STU_ID,STU_NAME) values
<foreach collection="list" item="item" index="index" separator=",">
(${item.get("clazz")},${item.get("stu")},${item.get("name")})
</foreach>
</insert>

最后建立测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String args[]) {
Logger logger = null;
logger = Logger.getLogger(MybatisExample.class.getName());
logger.setLevel(Level.DEBUG);
SqlSession sqlSession = null;
try {
sqlSession = study.mybatis.MybatisUtil.getSqlSessionFActory().openSession();
clazzStudent clazz = sqlSession.getMapper(clazzStudent.class);
List<Map<String,Object>> list =new ArrayList<Map<String, Object>>();
for(int i=0 ;i<3;i++){
Map<String,Object> itemmap =new HashMap<String, Object>();
itemmap.put("clazz",1);
itemmap.put("stu",i);
itemmap.put("name","'adsads'");
list.add(itemmap);
}
int n=clazz.insertToStudent(list);
System.out.println(n);
sqlSession.commit();
} finally {
sqlSession.close();
}
}

在这里需要注意得是 <foreach collection="list" item="item" index="index" separator=",">在这个里面的话collection="list"这里的list其实不需要和main方法中得list名称对应,也就是说在Java得main方法中将 List<Map<String,Object>> list =new ArrayList<Map<String, Object>>()这个list改成list1也可以插入多条语句,这里参数listcollection中得名称无关。

separator

分隔符,作用是foreach下面的语句执行完了之后之后用什么进行分割。而item则代表得是里面得那个map,

index

index代表的是索引,目前暂时没用到,所以就写一个索引

利用Java对象进行迭代

修改代码之后也可以利用Java对象进行传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Logger logger = null;
logger = Logger.getLogger(MybatisExample.class.getName());
logger.setLevel(Level.DEBUG);
SqlSession sqlSession = null;
try {
sqlSession = study.mybatis.MybatisUtil.getSqlSessionFActory().openSession();
clazzStudent clazz = sqlSession.getMapper(clazzStudent.class);
List<Student> list1 =new ArrayList<Student>();
for(int i=0 ;i<3;i++){
Student student =new Student();
student.setCLAZZ_ID(1);
student.setSTU_ID(i);
student.setSTU_NAME("测试");
list1.add(student);
}
int n=clazz.insertToStudentPojo(list1);
System.out.println(n);
sqlSession.commit();
} finally {
sqlSession.close();
}

但是使用对象传参的话需要注意得是在mapper文件中使用#符号,修改如下:

1
2
3
4
5
6
<insert id="insertToStudentPojo">
insert into student(CLAZZ_ID,STU_ID,STU_NAME) values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.CLAZZ_ID},#{item.STU_ID},#{item.STU_NAME})
</foreach>
</insert>

用List传值:

新建Dao层方法

1
Integer insertToStudentList(List<String> list);

新建mapper方法:

1
2
3
4
5
6
<insert id="insertToStudentList">
insert into student(STU_NAME) values
<foreach collection="list" item="item" index="index" separator=",">
(${item})
</foreach>
</insert>

测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static  void insertList(){
Logger logger = null;
logger = Logger.getLogger(MybatisExample.class.getName());
logger.setLevel(Level.DEBUG);
SqlSession sqlSession = null;
try {
sqlSession = study.mybatis.MybatisUtil.getSqlSessionFActory().openSession();
clazzStudent clazz = sqlSession.getMapper(clazzStudent.class);
List<String> list1 =new ArrayList<String>();
for(int i=0 ;i<3;i++){
list1.add(String.valueOf(i));
}
int n=clazz.insertToStudentList(list1);
System.out.println(n);
sqlSession.commit();
} finally {
sqlSession.close();
}
}

区别

在这里需要对Java对象传参使用得#和map传参得$进行一下区分。可以看下打印日志:
java对象传参使用#传参得日志:

1
2
3
DEBUG [main] - ==>  Preparing: insert into student(CLAZZ_ID,STU_ID,STU_NAME) values (?,?,?) , (?,?,?) , (?,?,?) 
DEBUG [main] - ==> Parameters: 1(Integer), 0(Integer), 测试(String), 1(Integer), 1(Integer), 测试(String), 1(Integer), 2(Integer), 测试(String)
DEBUG [main] - <== Updates: 3

java使用List进行传参:

1
2
3
4
DEBUG [main] - ==>  Preparing: insert into student(CLAZZ_ID,STU_ID,STU_NAME) values (1,0,'adsads') , (1,1,'adsads') , (1,2,'adsads') 
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Updates: 3
3

可以看到打印出来的日志发现$#在解析上得区别,$这个是先解析,生成了一个sql之后再执行,而#则是一个占位符,是在后期的时候动态加入的。

主键返回

mybatis的主键返回目前仅仅了解通过对象来返回。需要在mapper文件中加入一行配置即可:

1
2
3
4
5
6
7
8
9
<insert id="insertToStudentPojo">
<selectKey keyProperty="CLAZZ_ID" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into student(CLAZZ_ID,STU_ID,STU_NAME) values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.CLAZZ_ID},#{item.STU_ID},#{item.STU_NAME})
</foreach>
</insert>

keyProperty="CLAZZ_ID"表示的是需要返回的字段的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void pojo(){
Logger logger = null;
logger = Logger.getLogger(MybatisExample.class.getName());
logger.setLevel(Level.DEBUG);
SqlSession sqlSession = null;
try {
sqlSession = study.mybatis.MybatisUtil.getSqlSessionFActory().openSession();
clazzStudent clazz = sqlSession.getMapper(clazzStudent.class);
List<Student> list1 =new ArrayList<Student>();
for(int i=0 ;i<3;i++){
Student student =new Student();
student.setCLAZZ_ID(1);
student.setSTU_ID(i);
student.setSTU_NAME("测试");
list1.add(student);
}
int n=clazz.insertToStudentPojo(list1);
System.out.println(list1.get(2).getCLAZZ_ID());
System.out.println(n);
sqlSession.commit();
} finally {
sqlSession.close();
}
}

需要注意的是 System.out.println(list1.get(2).getCLAZZ_ID());因为是多条语句的插入,肯定是需要返回的最后一条插入后的主键,所以通过该方法便可以得到插入后的主键

总结

目前就暂时这么多了,源码以后再了解了。

作者

Somersames

发布于

2018-04-09

更新于

2021-04-05

许可协议

评论