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();