Vertica6在数据库的写入时对错误或者异常的处理和之前版本确实差别太大,但是不可否认新版本的支持确实要更合理一点,并且也慢慢的更接近JDBC规范。下面来看看在Vertica5和6上有什么区别吧
下面是数据库表的schema
CREATE TABLE public.t1 (
id int8 NOT NULL,
col1 varchar(32) NOT NULL,
col2 varchar(32) NOT NULL,
col3 varchar(32) NOT NULL,
CONSTRAINT "C_PRIMARY" PRIMARY KEY (id)
);
下面是测试用到的Java类,其中定义了Vertica5和6情况下使用的JDBC配置信息,在切换数据库的时候需要手动切换一下。
package com.googlecode.garbagecan.dbtest.vertica;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
public class VerticaTest {
// Vertica 5X
private static final String driver = "com.vertica.Driver";
private static final String url = "jdbc:vertica://perf4:5552/fkong2";
private static final String username = "pa80";
private static final String password = "fkong2";
// Vertica 6X
// private static final String driver = "com.vertica.jdbc.Driver";
// private static final String url = "jdbc:vertica://padev3:5433/padb";
// private static final String username = "pauser";
// private static final String password = "papassword";
public static void main(String[] args) throws Exception {
Connection conn = getConnection();
PreparedStatement ps = null;
try {
ps = conn.prepareStatement("insert into t1(id, col1, col2, col3)values(?,?,?,?)");
ps.setInt(1, 1);
ps.setObject(2, "value1");
ps.setObject(3, "value2");
ps.setObject(4, "value3");
ps.addBatch();
ps.setInt(1, 2);
ps.setObject(2, "value1");
ps.setObject(3, "value2");
ps.setObject(4, null); // duplicate primary key
// ps.setNull(4, Types.NULL); // duplicate primary key
ps.addBatch();
int[] results = ps.executeBatch();
System.out.println("No exception and results: " + Arrays.toString(results));
conn.commit();
} catch(SQLException ex) {
if (ex instanceof BatchUpdateException) {
System.out.println("SQLException and results: " + Arrays.toString(((BatchUpdateException) ex).getUpdateCounts()));
}
conn.rollback();
throw ex;
} finally {
conn.close();
}
}
private static Connection getConnection() throws Exception {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, username, password);
conn.setAutoCommit(false);
return conn;
}
}
上面代码需要向数据库表中插入两天记录,其中第一条应该可以正常写入,第二条我们人为的把col3列写入null,而schema中定义的这一列为not null,所以第二条数据应该写入失败。并且我们期望的行为是应该有异常抛出。下面我们来看看具体执行的时候是什么现象。
首先在Vertica5上运行,得到的结果如下
No exception and results: [1, -3]
这个结果说明第一条记录写入成功,第二条写入失败,并且没有出现异常,所以程序最终执行了conn.commit()操作,检查数据库,确实数据库中第一条记录写入成功了,第二条数据没有写入成功。
所以对于Vertica5来说,我们不能仅仅依靠是否抛异常来判断是否有错误发生,而是要在检查异常的基础上,还要检查ps.executeBatch()的执行返回结果,看其中是否有错误。
下面我们切换到Vertica6上来看看,执行结果如下
SQLException and results: [1, -3]
Exception in thread "main" java.sql.BatchUpdateException: [Vertica][VJDBC](100172) One or more rows were rejected by the server.
at com.vertica.jdbc.SStatement.processBatchResults(Unknown Source)
at com.vertica.jdbc.SPreparedStatement.executeBatch(Unknown Source)
at com.googlecode.garbagecan.dbtest.vertica.VerticaTest.main(VerticaTest.java:44)
首先出异常了,这是我们期望的行为,然后从异常里看写入的结果,发现第一条写入成功,第二条写入失败,所以程序执行了conn.rollback()操作回滚了所有记录。这个行为和我们通常在别的数据库上使用JDBC编程时的行为一致。
所以虽然Vertica6在写入时对错误或者异常的处理和之前版本差别很大,但是确实这些更新要更合理一点,并且也更符合JDBC规范。