程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 基於Java回想之JDBC的應用詳解

基於Java回想之JDBC的應用詳解

編輯:關於JAVA

基於Java回想之JDBC的應用詳解。本站提示廣大學習愛好者:(基於Java回想之JDBC的應用詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是基於Java回想之JDBC的應用詳解正文


雖然在現實開辟進程中,我們普通應用ORM框架來取代傳統的JDBC,例如Hibernate或許iBatis,但JDBC是Java用來完成數據拜訪的基本,控制它關於我們懂得Java的數據操作流程很有贊助。

JDBC的全稱是Java Database Connectivity。

JDBC對數據庫停止操作的流程:
•銜接數據庫
•發送數據要求,即傳統的CRUD指令
•前往操作成果集

JDBC中經常使用的對象包含:
•ConnectionManager
•Connection
•Statement
•CallableStatement
•PreparedStatement
•ResultSet
•SavePoint
一個簡略示例
我們來看上面一個簡略的示例,它應用JDK自帶的Derby數據庫,創立一張表,拔出一些記載,然後將記載前往:

一個簡略的JDBC示例
 private static void test1() throws SQLException
 {
     String driver = "org.apache.derby.jdbc.EmbeddedDriver";
     String dbURL = "jdbc:derby:EmbeddedDB;create=true";

     Connection con = null;
     Statement st = null;
     try
     {
         Class.forName(driver);
         con = DriverManager.getConnection(dbURL);
         st = con.createStatement();
         st.execute("create table foo(ID INT NOT NULL, NAME VARCHAR(30))");
         st.executeUpdate("insert into foo(ID,NAME) values(1, 'Zhang San')");

         ResultSet rs = st.executeQuery("select ID,NAME from foo");

         while(rs.next())
         {
             int id = rs.getInt("ID");
             String name = rs.getString("NAME");
             System.out.println("ID=" + id + "; NAME=" + name);
         }
     }
     catch(Exception ex)
     {
         ex.printStackTrace();
     }
     finally
     {
         if (st != null) st.close();
         if (con != null) con.close();
     }
 }

若何樹立數據庫銜接
下面的示例代碼中,樹立數據庫銜接的部門以下:

String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String dbURL = "jdbc:derby:EmbeddedDB;create=true";

Class.forName(driver);
con = DriverManager.getConnection(dbURL);

樹立數據庫銜接的進程,可以分為兩步:

1)加載數據庫驅動,即上文中的driver和Class.forName(dirver)

2)定位數據庫銜接字符串, 即dbURL和DriverManager.getConnection(dbURL)

分歧的數據庫,對應的dirver和dbURL分歧,但加載驅動和樹立銜接的方法是雷同的,即只須要修正下面driver和dbURL的值便可以了。

主動加載數據庫驅動
假如我們每次樹立銜接時,都要應用Class.forName(...)來手動加載數據庫驅動,如許會很費事,我們可以經由過程設置裝備擺設文件的方法,來保留數據庫驅動的信息。

我們可以在classpath中,即編譯出來的.class的寄存途徑,添加以下文件:

META-INF\services\java.sql.Driver

對應的內容就是JDBC驅動的全途徑,也就是下面driver變量的值:

org.apache.derby.jdbc.EmbeddedDriver

接上去,我們在法式中,就不須要再顯示的用Class.forName(...)來加載驅動了,它會被主動加載出去,當我們的數據庫產生變更時,只須要修正這個文件便可以了,例如當我們的數據庫由Derby變成MySQL時,只須要將上述的設置裝備擺設修正為:

com.mysql.jdbc.Driver

然則,須要留意一點,這裡只是設置裝備擺設了JDBC驅動的全途徑,並沒有包括jar文件的信息,是以,我們照樣須要將包括該驅動的jar文件手動的放置到法式的classpath中。

JDBC中的根本操作
關於數據庫操作來講,CRUD操作應當是最多見的操作了, 即我們常說的增、刪、查、改。

JDBC是應用Statement和ResultSet來完成這些操作的。

若何完成CRUD
上面是一個完成CRUD的示例:

JDBC完成根本的CRUD示例
 private static void insertTest() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     st.execute("insert into user(ID,NAME) values(1, 'Zhang San')");
     st.execute("insert into user(ID,NAME) values(2, 'Li Si')");
     st.execute("insert into user(ID,NAME) values(3, 'Wang Wu')");
     System.out.println("=====insert test=====");
     showUser(st);
     st.close();
     con.close();
 }

 private static void deleteTest() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     st.execute("delete from user where ID=3");
     System.out.println("=====delete test=====");
     showUser(st);
     st.close();
     con.close();
 }

 private static void updateTest() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     st.executeUpdate("update user set NAME='TEST' where ID=2");
     System.out.println("=====update test=====");
     showUser(st);
     st.close();
     con.close();
 }

 private static void showUser(Statement st) throws SQLException
 {
     ResultSet rs = st.executeQuery("select ID, NAME from user");
     while(rs.next())
     {
         int id = rs.getInt("ID");
         String name = rs.getString("NAME");
         System.out.println("ID:" + id + "; NAME=" + name);
     }
     rs.close();
 }

我們次序挪用下面的測試辦法:

insertTest();
deleteTest();
updateTest();

履行成果以下:

=====insert test=====
ID:1; NAME=Zhang San
ID:2; NAME=Li Si
ID:3; NAME=Wang Wu
=====delete test=====
ID:1; NAME=Zhang San
ID:2; NAME=Li Si
=====update test=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST

下面代碼中的showUser辦法會把user表中的一切記載打印出來。

若何挪用存儲進程
存儲進程是做數據庫開辟時常常應用的技巧,它可以經由過程節儉編譯時光的方法來晉升體系機能,我們這裡的示例應用MySQL數據庫。

若何挪用不帶參數的存儲進程
假定我們如今有一個簡略的存儲進程,它只是前往user表中的一切記載,存儲進程以下:

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetUser`()
BEGIN
select ID,NAME from user;
END

我們可使用CallableStatement來挪用存儲進程:

挪用存儲進程示例一
 private static void execStoredProcedureTest() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     CallableStatement cst = con.prepareCall("call GetUser()");
     ResultSet rs = cst.executeQuery();
     while(rs.next())
     {
         int id = rs.getInt("ID");
         String name = rs.getString("NAME");
         System.out.println("ID:" + id + "; NAME=" + name);
     }
     rs.close();
     cst.close();
     con.close();
 }

它的履行成果以下:

ID:1; NAME=Zhang San
ID:2; NAME=TEST

若何挪用帶參數的存儲進程
MySQL的存儲進程中的參數分為三種:in/out/inout,我們可以把in看作入力參數,out看作出力參數,JDBC對這兩品種型的參數設置方法分歧:

1)in, JDBC應用相似於cst.set(1, 10)的方法來設置

2)out,JDBC應用相似於cst.registerOutParameter(2, Types.VARCHAR);的方法來設置

我們來看一個in參數的示例,假定我們願望前往ID為特定值的user信息,存儲進程以下:

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetUserByID`(in id int)
 BEGIN
 set @sqlstr=concat('select * from user where ID=', id);
 prepare psmt from @sqlstr;
 execute psmt;
 END

Java的挪用代碼以下:

JDBC挪用存儲進程示例二
 private static void execStoredProcedureTest2(int id) throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     CallableStatement cst = con.prepareCall("call GetUserByID(?)");
     cst.setInt(1, id);
     ResultSet rs = cst.executeQuery();
     while(rs.next())
     {
         String name = rs.getString("NAME");
         System.out.println("ID:" + id + "; NAME=" + name);
     }
     rs.close();
     cst.close();
     con.close();
 }

我們履行上面的語句:

execStoredProcedureTest2(1);

成果以下:

ID:1; NAME=Zhang San

關於out類型的參數,挪用方法相似,不再贅述。

獲得數據庫和成果集的metadata信息
在JDBC中,我們不只可以或許對數據停止操作,我們還能獲得數據庫和成果集的元數據信息,例如數據庫的稱號、驅動信息、表信息;成果集的列信息等。

獲得數據庫的metadata信息
我們可以經由過程connection.getMetaData辦法來獲得數據庫的元數據信息,它的類型是DatabaseMetaData。

獲得數據庫的元數據信息
 private static void test1() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/mysql";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");

     DatabaseMetaData dbmd = con.getMetaData();

     System.out.println("數據庫:" + dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
     System.out.println("驅動法式:" + dbmd.getDriverName() + " " + dbmd.getDriverVersion());

     ResultSet rs = dbmd.getTables(null, null, null, null);
     System.out.println(String.format("|%-26s|%-9s|%-9s|%-9s|", "表稱號","表種別","表類型","表形式"));       
     while(rs.next())
     {
         System.out.println(String.format("|%-25s|%-10s|%-10s|%-10s|",
                 rs.getString("TABLE_NAME"),rs.getString("TABLE_CAT"),
                 rs.getString("TABLE_TYPE"), rs.getString("TABLE_SCHEM")));
     }
 }

這裡我們應用的數據庫是MySQL中自帶的默許數據庫:mysql,它會記載全部數據庫辦事器中的一些信息。上述代碼履行成果以下:

數據庫:MySQL 5.5.28
驅動法式:MySQL-AB JDBC Driver mysql-connector-java-5.0.4 ( $Date: 2006-10-19 17:47:48 +0200 (Thu, 19 Oct 2006) $, $Revision: 5908 $ )
|表稱號                       |表種別      |表類型      |表形式      |
|columns_priv             |mysql     |TABLE     |null      |
|db                       |mysql     |TABLE     |null      |
|event                    |mysql     |TABLE     |null      |
|func                     |mysql     |TABLE     |null      |
。。。

因為mysql中表比擬多,上述成果只截取了一部門。

獲得成果集的元數據信息
我們可以經由過程應用resultset.getMetaData辦法來獲得成果集的元數據信息,它的類型是ResultSetMetaData。

獲得成果集的元數據信息
 private static void test2() throws SQLException
 {
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     ResultSet rs = st.executeQuery("select ID, NAME from user");
     ResultSetMetaData rsmd = rs.getMetaData();
     for (int i = 1; i <= rsmd.getColumnCount(); i++)
     {
         System.out.println("Column Name:" + rsmd.getColumnName(i) + "; Column Type:" + rsmd.getColumnTypeName(i));
     }
 }

它的履行成果以下:

Column Name:ID; Column Type:INTEGER UNSIGNED
Column Name:NAME; Column Type:VARCHAR

可以看到,它前往類成果集中每列的稱號和類型。

基於ResultSet的操作
當我們須要對數據庫停止修正時,除上述經由過程Statement完成操作外,我們也能夠借助ResultSet來完成。

須要留意的是,在這類情形下,我們界說Statement時,須要添加參數。

Statement結構函數可以包括3個參數:

•resultSetType,它的取值包含:ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE,默許情形下,該參數的值是ResultSet.TYPE_FORWARD_ONLY。
•resultSetConcurrency,它的取值包含:ResultSet.CONCUR_READ_ONLY 或 ResultSet.CONCUR_UPDATABLE,默許情形下,該參數的值是ResultSet.CONCUR_READ_ONLY。
•resultSetHoldability,它的取值包含:ResultSet.HOLD_CURSORS_OVER_COMMIT 或 ResultSet.CLOSE_CURSORS_AT_COMMIT。
為了使得ResultSet可以或許對數據停止操作我們須要:

•將resultSetType設置為ResultSet.TYPE_SCROLL_SENSITIVE。
•將resultSetConcurrency設置為ResultSet.CONCUR_UPDATABLE。
在經由過程ResultSet對數據停止調劑的進程中,上面辦法能夠會被挪用:

•resultset.last()
•resultset.first()
•resultset.moveToInsertRow()
•resultset.absolute()
•resultset.setxxx()
•resultset.updateRow()
•resultset.insertRow()
上面是一個經由過程ResultSet對數據停止增、刪、改的示例:

經由過程ResultSet對數據停止增、刪、改
 private static void getResultCount() throws SQLException
 {
     System.out.println("=====Result Count=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
     ResultSet rs = st.executeQuery("select * from user");
     rs.last();
     System.out.println("前往成果的條數:"+ rs.getRow());
     rs.first();

     rs.close();
     st.close();
     con.close();
 }

 private static void insertDataToResultSet() throws SQLException
 {
     System.out.println("=====Insert=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
     ResultSet rs = st.executeQuery("select ID,NAME from user");
     rs.moveToInsertRow();
     rs.updateInt(1, 4);
     rs.updateString(2, "Xiao Ming");
     rs.insertRow();
     showUser(st);

     rs.close();
     st.close();
     con.close();
 }

 private static void updateDataToResultSet() throws SQLException
 {
     System.out.println("=====Update=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
     ResultSet rs = st.executeQuery("select * from user");
     rs.last();
     int count = rs.getRow();
     rs.first();
     rs.absolute(count);
     rs.updateString(2, "Xiao Qiang");
     rs.updateRow();
     showUser(st);

     rs.close();
     st.close();
     con.close();
 }

 private static void delDataFromResultSet() throws SQLException
 {
     System.out.println("=====Delete=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
     ResultSet rs = st.executeQuery("select * from user");
     rs.last();
     int count = rs.getRow();
     rs.first();
     rs.absolute(count);
     rs.deleteRow();
     showUser(st);

     rs.close();
     st.close();
     con.close();
 }

分離挪用上述辦法:

getResultCount();
insertDataToResultSet();
updateDataToResultSet();
delDataFromResultSet();

履行成果以下:

=====Result Count=====
前往成果的條數:2
=====Insert=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:4; NAME=Xiao Ming
=====Update=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:4; NAME=Xiao Qiang
=====Delete=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST

可以看到我們對ID為4的記載停止了拔出、更新和刪除操作。

預處置和批處置
預處置和批處置都是用來晉升體系機能的方法,一種是應用數據庫的緩存機制,一種是應用數據庫一次履行多條語句的方法。

預處置
數據庫辦事器吸收到Statement後,普通會解析Statement、剖析能否有語法毛病、定制最優的履行籌劃,這個進程能夠會下降體系的機能。普通的數據庫辦事器都這對這類情形,設計了緩存機制,當數據庫吸收到指令時,假如緩存中曾經存在,那末就不再解析,而是直接運轉。

這裡雷同的指令是指sql語句完整一樣,包含年夜小寫。

JDBC應用PreparedStatement來完成預處置:

預處置示例
 private static void test1() throws SQLException
 {
     System.out.println("=====Insert a single record by PreparedStatement=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");
     pst.setInt(1, 5);
     pst.setString(2, "Lei Feng");
     pst.executeUpdate();
     showUser(pst);
     pst.close();
     con.close();
 }

履行成果以下:

=====Insert a single record by PreparedStatement=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng

批處置
批處置是應用數據庫一次履行多條語句的機制來晉升機能,如許可以免屢次樹立銜接帶來的機能喪失。

批處置應用Statement的addBatch來添加指令,應用executeBatch辦法來一次履行多條指令:

批處置示例
 private static void test2() throws SQLException
 {
     System.out.println("=====Insert multiple records by Statement & Batch=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     st.addBatch("insert into user(id,name) values(6,'Xiao Zhang')");
     st.addBatch("insert into user(id,name) values(7,'Xiao Liu')");
     st.addBatch("insert into user(id,name) values(8,'Xiao Zhao')");
     st.executeBatch();
     showUser(st);
     st.close();
     con.close();
 }

履行成果以下:

=====Insert multiple records by Statement & Batch=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:6; NAME=Xiao Zhang
ID:7; NAME=Xiao Liu
ID:8; NAME=Xiao Zhao

預處置和批處置相聯合
我們可以把預處置和批處置聯合起來,應用數據庫的緩存機制,一次履行多條語句:

預處置和批處置相聯合的示例
 private static void test3() throws SQLException
 {
     System.out.println("=====Insert multiple records by PreparedStatement & Batch=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");
     pst.setInt(1, 9);
     pst.setString(2, "Xiao Zhang");
     pst.addBatch();
     pst.setInt(1, 10);
     pst.setString(2, "Xiao Liu");
     pst.addBatch();
     pst.setInt(1, 11);
     pst.setString(2, "Xiao Zhao");
     pst.addBatch();
     pst.executeBatch();
     showUser(pst);
     pst.close();
     con.close();
 }

履行成果以下:

=====Insert multiple records by PreparedStatement & Batch=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:9; NAME=Xiao Zhang
ID:10; NAME=Xiao Liu
ID:11; NAME=Xiao Zhao

數據庫事務
談到數據庫開辟,事務是一個弗成躲避的話題,JDBC默許情形下,是每步都主動提交的,我們可以經由過程設置connection.setAutoCommit(false)的方法來強迫封閉主動提交,然後經由過程connection.commit()和connection.rollback()來完成事務提交和回滾。

簡略的數據庫事務
上面是一個簡略的數據庫事務的示例:

簡略的數據庫事務示例
 private static void transactionTest1() throws SQLException
 {
     System.out.println("=====Simple Transaction test=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     try
     {
         con.setAutoCommit(false);
         st.executeUpdate("insert into user(id,name) values(12, 'Xiao Li')");
         con.commit();
     }
     catch(Exception ex)
     {
         ex.printStackTrace();
         con.rollback();
     }
     finally
     {
         con.setAutoCommit(true);
         showUser(st);
         if (st != null) st.close();
         if (con != null) con.close();
     }
 }

持續履行上述辦法兩次,我們可以得出上面的成果:

=====Simple Transaction test=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:12; NAME=Xiao Li
=====Simple Transaction test=====
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:12; NAME=Xiao Li
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry '12' for key 'PRIMARY'
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)
    at com.mysql.jdbc.Connection.execSQL(Connection.java:3170)
    at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1316)
    at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1235)
    at sample.jdbc.mysql.ResultSetSample.transactionTest1(ResultSetSample.java:154)
    at sample.jdbc.mysql.ResultSetSample.main(ResultSetSample.java:17)

可以看到,第一次挪用時,操作勝利,事務提交,向user表中拔出了一筆記錄;第二次挪用時,產生主鍵抵觸異常,事務回滾。

帶有SavePoint的事務
當我們的事務操作中包括多個處置,但我們有時願望一些操作完成後可以先提交,如許可以免全部事務的回滾。JDBC應用SavePoint來完成這一點。

帶有SavePoint的事務示例
 private static void transactionTest2() throws SQLException
 {
     System.out.println("=====Simple Transaction test=====");
     String dbURL = "jdbc:mysql://localhost/test";
     Connection con = DriverManager.getConnection(dbURL, "root", "123");
     Statement st = con.createStatement();
     Savepoint svpt = null;
     try
     {
         con.setAutoCommit(false);
         st.executeUpdate("insert into user(id,name) values(13, 'Xiao Li')");
         st.executeUpdate("insert into user(id,name) values(14, 'Xiao Wang')");
         svpt = con.setSavepoint("roll back to here");
         st.executeUpdate("insert into user(id,name) values(15, 'Xiao Zhao')");
         st.executeUpdate("insert into user(id,name) values(13, 'Xiao Li')");
         con.commit();
     }
     catch(Exception ex)
     {
         ex.printStackTrace();
         con.rollback(svpt);
     }
     finally
     {
         con.setAutoCommit(true);
         showUser(st);
         if (st != null) st.close();
         if (con != null) con.close();
     }
 }

履行成果以下:

=====Simple Transaction test=====
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry '13' for key 'PRIMARY'
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)
    at com.mysql.jdbc.Connection.execSQL(Connection.java:3170)
    at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1316)
    at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1235)
    at sample.jdbc.mysql.ResultSetSample.transactionTest2(ResultSetSample.java:185)
    at sample.jdbc.mysql.ResultSetSample.main(ResultSetSample.java:18)
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:13; NAME=Xiao Li
ID:14; NAME=Xiao Wang

可以看到終究事務報出了主鍵抵觸異常,事務回滾,然則仍然向數據庫中拔出了ID為13和14的記載。

別的,在肯定SavePoint後,ID為15的記載並沒有被拔出,它是經由過程事務停止了回滾。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved