Play虽然很快捷,但也终究是存在不足之处,当批量操作时,只能用调用JPA去执行原生SQL,
本人这里写了批量修改与批量新增的操作这两种操作。
网上查了很多,基本都是
//查到的第一种
for (int i = 0; i < list.size(); i++) {
em.persist(list.get(i));
if (i % 100 == 0) {//一次一百条插入
em.flush();
em.clear();
}
}
//查到的第二种
for(DvdRateConfig rate : set) {
if(i%100==0) {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>flush");
JPA.em().flush();
JPA.em().clear();
}
rate.save();
}
两种方式都是调用flush更新到数据库,无非就是以
insert in to table values(…)
insert in to table values(…)
.
.
.
这种方式每100条执行一次,但从代码来看,以每一百条提交,虽然比单个提交效率提高很多,但也并不是我想要的结果(insert in to table values(…),(…)),所以还是需要JPA执行原生SQL,下面介绍批量新增与更新的批量操作:
1批量新增
/**
* insert into test (admin_id, subject_id, update_time,status,name) values(...),(...);
*/
public static void testis() {
List<Test1> list = new ArrayList<Test1>();
for (int i = 0; i < 10; i++) {
Test1 t = new Test1();
t.admin_id = 1L;
t.subject_id = 1L;
t.status = 2;
t.update_time = new Date();
t.name = "'测试增加"+(i+1)+"号'";
list.add(t);
}
StringBuffer insertSql = new StringBuffer();
insertSql.append("insert into test (admin_id, subject_id, update_time,status,name) values");
for (int i = 0; i < list.size(); i++) {
insertSql.append("(");
insertSql.append(list.get(i).admin_id+",");
insertSql.append(list.get(i).subject_id+",");
insertSql.append("str_to_date('"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(list.get(i).update_time).toString()+"','%Y-%m-%d %H:%i:%s'),");
insertSql.append(list.get(i).status+",");
insertSql.append(list.get(i).name);
insertSql.append(")");
if(i!=list.size()-1){
insertSql.append(",");
}
}
Query createNativeQuery = JPA.em().createNativeQuery(insertSql.toString());
int executeUpdate = createNativeQuery.executeUpdate();
System.out.println(executeUpdate);//影响条数
}
2批量修改
/**
*
* UPDATE test
* SET name = CASE id
* WHEN 426 THEN '测试修改426'
* WHEN 427 THEN '测试修改427'
* END
* WHERE id IN (426,427)
*/
public static void testus() {
List<Test1> list = new ArrayList<Test1>();
for (int i = 0; i < 10; i++) {
Test1 t = new Test1();
t.id = 456+Long.parseLong(i+"");
t.admin_id = 2L;
t.subject_id = 3L;
t.status = 2;
t.update_time = new Date();
t.name = "'测试修改"+(i+100)+"号'";
list.add(t);
}
String updateSql = "update test set admin_id = case id adminIdWhenThen end, subject_id = case id subjectIdWhenThen end, name = case id nameWhenThen end where id in (whereIds)";
StringBuffer adminIdWhenThen = new StringBuffer();
StringBuffer subjectIdWhenThen = new StringBuffer();
StringBuffer nameWhenThen = new StringBuffer();
StringBuffer whereIds = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
adminIdWhenThen.append(" when "+list.get(i).id+" then "+list.get(i).admin_id);
subjectIdWhenThen.append(" when "+list.get(i).id+" then "+list.get(i).subject_id);
nameWhenThen.append(" when "+list.get(i).id+" then "+list.get(i).name+"");
whereIds.append(list.get(i).id);
if(i != list.size()-1){
whereIds.append(",");
}
}
updateSql = updateSql.replace("adminIdWhenThen", adminIdWhenThen.toString()).replace("subjectIdWhenThen", subjectIdWhenThen.toString())
.replace("nameWhenThen", nameWhenThen.toString()).replace("whereIds", whereIds.toString());
Query createNativeQuery = JPA.em().createNativeQuery(updateSql.toString());
int executeUpdate = createNativeQuery.executeUpdate();
System.out.println(executeUpdate);
}
需要特别注意,这里有几处坑:
1、createNativeQuery是执行原生SQL的方法,createQuery是执行HQL语句的方法。
2、拼接SQL时,属性为字符时,应该用’'或""包住,完全按照SQL规范,例:‘测试’
3、同上,属性为时间类型时,需要SimpleDateFormat格式化一下,再用STR_TO_DATE(str,format)转换一下,特别需要注意,这里不能用双引号包住,如果是"2018-11-20 10:10:10"这种格式会报类型错误,因为数据库是dateTime类型,所以需要转换。
3.1、附上mysql时间类型转换:
STR_TO_DATE(str,format)–字符转时间
DATE_FORMAT(date,format)–时间转字符
%Y:代表4位的年份
%y:代表2为的年份
%m:代表月, 格式为
%d:代表月份中的天数
%H:代表小时,格式为(00……23)
%h: 代表小时,格式为(01……12)
%i: 代表分钟
%S:代表 秒
4、如果数据量大时,需要分批操作,可以调用以下方法来手动批量提交
JPA.em().getTransaction().begin();
JPA.em().getTransaction().commit();
JPA.em().getTransaction().rollback();