场景
数据迁移完成后需要对库中序列进行重置,。
方法
三种常见方式
删除--重建
这种方式下简单的序列重建会影响业务逻辑处理无法适应原有序列参数规则不一致的情况,但如果序列参数一致的情况下此种办法比较简单还有效率。
临时修改序列步长,而后还原(PL/SQL采用此种方式)
这种方式通过先修改序列步长然后通过NEXTVAL自增序列得到目标值,最后再将序列步长还原为原始值,如下SQL
- ALTER SEQUENCE SEQ_ACCOUNT_BALANCE INCREMENT BY 1000;
- SELECT SEQ_ACCOUNT_BALANCE.NEXTVAL FROM DUAL;
- ALTER SEQUENCE SEQ_ACCOUNT_BALANCE INCREMENT BY 1;
-
在修改某个具体序列时经常使用此方法,但如果批量操作序列则操作步骤较上一步要多了一步。
循环递增序列值
这种办法非常安全但低效率,如下SQL:
- FOR I IN 1 .. 1000 LOOP
- SELECT SEQ_ACC_ID.NEXTVAL INTO SAI FROM DUAL;
- END LOOP;
本人项目需求:
迁移数据,序列的初始值为数据表中序列对应主键ID的最大值。由于表和序列没有关联,本人将表、序列和主键值对应在配置文件中。如图:
主键ID,序列和表字段封装到一个实体类中,则读取出来存放到List中。
将List的值转变成执行的SQL语句,在此,一个序列改变初始值,则删除序列和创建序列同时执行,我是将执行一个序列的这两个语句放在数组里,则多个序列则存数组的集合
Controller.java
//start 改变序列的初始值
try {
//获取数据
List<SequenceMessage> seqmessageList = ParseXml.getSequenceList();
Map<String, List<String>> resultmap = baseservice.doWork(seqmessageList);
logsb.append("序列初始值改变<BR>总共序列个数"+seqmessageList.size()+"<br>");
List<String> falseResult = resultmap.get("false");
List<String> trueResult = resultmap.get("true");
logsb.append("执行序列错误有"+falseResult.size()+"个,执行序列正确有"+trueResult.size()+"个,无数据表"+(seqmessageList.size()-falseResult.size()-trueResult.size())+"<br>");
if(falseResult.size() > 0){
logsb.append("失败执行语句以下有:<br>");
for (int i = 0; i < falseResult.size(); i++) {
logsb.append(falseResult.get(i)+"<br>");
}
}
if(trueResult.size() >0){
logsb.append("正确执行语句以下有:<br>");
for (int i = 0; i < trueResult.size(); i++) {
logsb.append(trueResult.get(i)+"<br>");
}
}
} catch (Exception e) {
logsb.append("改变序列初始值发生异常:"+e.toString()+"<br><br>");
e.printStackTrace();
}
baseservice.java
public Map<String, List<String>> doWork(List<SequenceMessage> seqmessageList){
Connection conn = getConnection();
Map<String, List<String>> resultmap = new HashMap<String, List<String>>();
List<String> falseResult = new ArrayList<String>();
List<String> trueResult = new ArrayList<String>();
//start 获取表和序列和字段之间的关系
List<String[]> seqDDLArray = new ArrayList<String[]>();
for (int i = 0; i < seqmessageList.size(); i++) {
SequenceMessage seqmsg = seqmessageList.get(i);
String id = seqmsg.getId();
String tname = seqmsg.getTablename();
String seqname = seqmsg.getSeqname();
String maxsql = "select max(" + id + ") from " + tname;
// 执行根据该主键ID获取该对应表中的最大值
Object[] obj = null;
try {
obj = (Object[]) basedao.queryForArrayList(maxsql).get(0);
String objstr = obj[0] + "";
if (!"null".equals(objstr)) {
seqDDLArray.add(rebuildSEQ(seqname,Integer.parseInt(objstr)));
}
} catch (Exception e) {
e.printStackTrace();
falseResult.add(e.toString());
continue;
}
}
//start 循环执行删除序列和创建序列
for (int i = 0; i < seqDDLArray.size(); i++) {
//同一个序列 删除和创建同时执行
String[] sqlattr=seqDDLArray.get(i);
try {
boolean flag =basedao.updateBatch(sqlattr, conn);
if(!flag){
for (int j = 0; j <sqlattr.length; j++) {
falseResult.add(sqlattr[j]);
}
}else{
for (int j = 0; j <sqlattr.length; j++) {
trueResult.add(sqlattr[j]);
}
}
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
resultmap.put("false", falseResult);
resultmap.put("true", trueResult);
DbUtils.closeQuietly(conn);
return resultmap;
}
basedao.java
/**
* 执行批量
*
* @param sqlArray
* @throws SQLException
*/
public boolean updateBatch(String[] sqlArray, Connection conn)
throws SQLException {
boolean flag = false;
conn.setAutoCommit(false);
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
for (String tmpSql : sqlArray) {
stmt.addBatch(tmpSql);
}
int[] rtnArr = stmt.executeBatch();
conn.commit();
if (rtnArr.length > 0) {
flag = true;
}
return flag;
}
返回类型是由于我需求是要将后台代码返回给前端展示,就直接在后台拼接代码了。代码应该可以看懂
我这个代码是执行一个序列的操作不成功,继续走下一步,错误和正确执行的返回给客户端展示
界面就不展示了
参照http://blog.csdn.net/a316212802/article/details/40297115