mysql批量插入与oracle批量插入不同
一、搭建数据库
tbl_employee表【d_id 是外键 对应 tbl_dept表】
id last_name gender email d_id 1 mike 0 [email protected] 1 2 book 0 [email protected] 2 3 tom 1 [email protected] 2 4 jerry 1 [email protected] 1
tbl_dept表:
id dept_name 1 开发部 2 测试部
二、编辑javabean
package com.mybatis.bean; public class Employee { private Integer id; private String lastName; private String email; private String gender; private Department department; public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]"; } /***** 关键是 这个地方啊 出了 问题 ****/ public Employee() { super(); } /*****/ public Employee(Integer id,String lastName, String email, String gender){ this.id =id; this.lastName =lastName; this.email =email; this.gender =gender; } public Employee(Integer id,String lastName, String email, String gender,Department dep){ this.id =id; this.lastName =lastName; this.email =email; this.gender =gender; this.department =dep; } // 历史教训 ,一开始 没有添加 无参构造函数,而添加了下面这个函数 // public Employee(Integer id,String lastName, String email, String gender,int temp){ // this.id =id; // this.lastName =lastName; // this.email =email; // this.gender =gender; // // System.out.println(" id:"+id+" lastName:"+lastName+" email:"+email+" gender:"+gender+" temp:"+temp); // } }
package com.mybatis.bean; import java.util.List; public class Department { private Integer id; private String departmentName; private List<Employee> employees; public Department() { } public Department(int id){ this.id = id; } public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } @Override public String toString() { return "Department [id=" + id + ", departmentName=" + departmentName + "]"; } }
三、编辑junit测试
@Test public void testBatchSave() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class); List<Employee> emps = new ArrayList<>(); emps.add(new Employee(null, "smith0x1", "[email protected]", "1" , new Department(1) )); emps.add(new Employee(null, "allen0x1", "[email protected]", "0" , new Department(1) )); mapper.addEmps(emps); openSession.commit(); }finally{ openSession.close(); } }
四、编辑SQl映射文件
1、mysql 版
<!--MySQL下批量保存:可以foreach遍历 mysql支持values(),(),()语法-->
<!-- 批量保存 --> <!--public void addEmps(@Param("emps")List<Employee> emps); --> <!--MySQL下批量保存:可以foreach遍历 mysql支持values(),(),()语法--> <insert id="addEmps"> insert into tbl_employee(last_name,email,gender,d_id) values <foreach collection="emps" item="emp" separator=","> (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id}) </foreach> </insert><!-- --> <!-- 这种方式需要数据库连接属性allowMultiQueries=true; 这种分号分隔多个sql可以用于其他的批量操作(删除,修改) --> <!-- <insert id="addEmps"> <foreach collection="emps" item="emp" separator=";"> insert into tbl_employee(last_name,email,gender,d_id) values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id}) </foreach> </insert> -->
mysql补充:在mysql配置时,我们可能需要配置 allowMultiQueries=true
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
若一个sql中通过分号分割(或包含)了多个独立sql的话,如: select 'hello';select 'world' 就会报如下错: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select 'world'' at line 1 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 当若显式设置allowMultiQueries为true的话,就可以正常执行不会报错.如下所示: String url = "jdbc:mysql://localhost:3306?allowMultiQueries=true"; 官方文档解释: allowMultiQueries Allow the use of ';' to delimit multiple queries during one statement (true/false), defaults to 'false', and does not affect the addBatch() and executeBatch() methods, which instead rely on rewriteBatchStatements. Default: false Since version: 3.1.1
2、oracle版
<!-- Oracle数据库批量保存: Oracle不支持values(),(),() Oracle支持的批量方式 1、多个insert放在begin - end里面 begin insert into employees(employee_id,last_name,email) values(employees_seq.nextval,'test_001','[email protected]'); insert into employees(employee_id,last_name,email) values(employees_seq.nextval,'test_002','[email protected]'); end; 2、利用中间表: insert into employees(employee_id,last_name,email) select employees_seq.nextval,lastName,email from( select 'test_a_01' lastName,'test_a_e01' email from dual union select 'test_a_02' lastName,'test_a_e02' email from dual union select 'test_a_03' lastName,'test_a_e03' email from dual ) -->
实际写法:
<insert id="addEmps" databaseId="oracle"> <!-- oracle第一种批量方式 --> <!-- <foreach collection="emps" item="emp" open="begin" close="end;"> insert into employees(employee_id,last_name,email) values(employees_seq.nextval,#{emp.lastName},#{emp.email}); </foreach> --> <!-- oracle第二种批量方式 --> insert into employees( <!-- 引用外部定义的sql --> <include refid="insertColumn"> <property name="testColomn" value="abc"/> </include> ) <foreach collection="emps" item="emp" separator="union" open="select employees_seq.nextval,lastName,email from(" close=")"> select #{emp.lastName} lastName,#{emp.email} email from dual </foreach> </insert>
特别提醒一下:下面的引用其实就是 待插入的 各个字段啦。
<!-- 引用外部定义的sql --> <include refid="insertColumn"> <property name="testColomn" value="abc"/> </include>
用法说明:不是只能用在批量插入中,也可以用在其他数据操作中,因为只是对SQL片段的抽取。
<!-- 抽取可重用的sql片段。方便后面引用 1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用 2、include来引用已经抽取的sql: 3、include还可以自定义一些property,sql标签内部就能使用自定义的属性 include-property:取值的正确方式${prop}, #{不能使用这种方式} 4、employee_id,last_name,email,${prop} 这个oracle插入 其实等价于【当然数据库有没有相应字段是另一回事,在这里只是用来演示】 employee_id,last_name,email,abc 5、_databaseId 是 mybatis 内置参数,和在 全局配置文件中,标记的数据库 名是 一样的 --> <sql id="insertColumn"> <if test="_databaseId=='oracle'"> employee_id,last_name,email,${prop} </if> <if test="_databaseId=='mysql'"> last_name,email,gender,d_id </if> </sql>