JavaEE之JDBC编程[详解]
1.数据库简介
数据库(DB,Data Base )
数据库管理系统(DBMS,Data Base Management System)
关系型数据库(RDB)
关系型数据库管理系统(RDBMS)
SQL语言(Structured Query Language):使用关系模型的数据库语言,用于和各类数据库的交互,提供通用的数据管理和查询功能。
常用SQL指令:(CURD)
SELECT 、INSERT、DELETE、UPDATE、CREATE、DROP
ODBC(Open DataBase Connectivity,开放式数据库互连):数据库系统应用程序接口规范。
支持应用程序以标准的ODBC函数和SQL语句操作各种不同类型的数据库。
2.JDBC(Java DataBase Connectivity)
JDBC功能:
①支持基本SQL语句,在Java程序中实现数据库操作功能并简化操作过程
②提供多样化的数据库连接方法
③为各种不同的数据库提供统一的操作界面
JDBC API:
java.sql. DriverManager类:驱动管理类
java.sql.Driver接口
java.sql.Connection接口:与特定的数据库之间的连接
java.sql.Statement接口:指定数据库连接和要执行的sql表达式就可以执行sql语句
java.sql.ResultSet接口:返回结果
原理:首先要将不同的数据库驱动程序加载到驱动程序管理器
3.JDBC驱动程序
数据库驱动程序(DataBase Driver)
JDBC驱动程序分类:
第一类:JDBC-OCBC桥(并不常用)
第二类:Java到本地API(本地API是指本机安装了目标数据库的客户端,但是不通用,因为必须要安装客户端)
第三类:Java到网络协议(通过网络协议实现数据库操作,服务器端需要有特定的协议)
第四类:Java到数据库协议(速度最快,但是不具备通用性,必须要为各种数据库配置相应的协议)
4.数据库URL
JDBC技术中使用数据库URL来标识目标数据库 数据库URL格式:jdbc:<子协议名>:<子名称>
"jdbc"为协议名,确定不变;
<子协议名>指定目标数据库的种类和具体连接方式;
<子名称>指定具体的数据库/数据源连接信息(如数据库服务器的IP地址/通信端口号、ODBC数据源名称、连接用户名/密码等)。
子名称的格式和内容随子协议的不同而改变。
举例:
jdbc:oracle:thin:@166.111.78.98:1521:ora9
jdbc:microsoft:sqlserver://127.0.0.1:1433
jdbc:microsoft:sqlserver://127.0.0.1:1433;databasename=pubs
关于oracle的thin和oci的方式访问的区别请见:http://www.cnblogs.com/phoebus0501/archive/2011/05/12/2044725.html
5.JDBC编程基本步骤
1. 加载 驱 动 程 序 ( 向 系 统 注 册 所 需 的 JDBC 驱 动 程序);
2. 建立到指定数据库的连接;
3. 提交数据库查询;
4. 取得查询结果
MySQL 数据库的一个简单实例:
package v512.chap18; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement; public class JDBCExample { public static void main(String[] args) {
try {
Class.forName("org.gjt.mm.mysql.Driver");
String url ="jdbc:mysql://localhost/blog";
Connection connection = DriverManager.getConnection(url,"root","yinger");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select id,title from blog");
while (resultSet.next()) {
System.err.println(resultSet.getInt("id")+":"+resultSet.getString("title"));
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1. MySQL(http://www.mysql.com)mm.mysql-2.0.2-bin.jar
Class.forName( "org.gjt.mm.mysql.Driver" );
cn = DriverManager.getConnection( "jdbc:mysql://MyDbComputerNameOrIP:3306/myDatabaseName", sUsr, sPwd );
2. PostgreSQL(http://www.de.postgresql.org)pgjdbc2.jar
Class.forName( "org.postgresql.Driver" );
cn = DriverManager.getConnection( "jdbc:postgresql://MyDbComputerNameOrIP/myDatabaseName", sUsr, sPwd );
3. Oracle(http://www.oracle.com/ip/deploy/database/oracle9i/)classes12.zip
Class.forName( "oracle.jdbc.driver.OracleDriver" );
cn = DriverManager.getConnection( "jdbc:oracle:thin:@MyDbComputerNameOrIP:1521:ORCL", sUsr, sPwd ); 例如:
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:orcale";
conn = DriverManager.getConnection(url,"scott","tiger"); 4. Sybase(http://jtds.sourceforge.net)jconn2.jar
Class.forName( "com.sybase.jdbc2.jdbc.SybDriver" );
cn = DriverManager.getConnection( "jdbc:sybase:Tds:MyDbComputerNameOrIP:2638", sUsr, sPwd );
// (Default-Username/Password: "dba"/"sql")
5. Microsoft SQLServer(http://jtds.sourceforge.net)
Class.forName( "net.sourceforge.jtds.jdbc.Driver" );
cn = DriverManager.getConnection( "jdbc:jtds:sqlserver://MyDbComputerNameOrIP:1433/master", sUsr, sPwd );
6. Microsoft SQLServer(http://www.microsoft.com)
Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" );
cn = DriverManager.getConnection( "jdbc:microsoft:sqlserver://MyDbComputerNameOrIP:1433;databaseName=master", sUsr, sPwd );
7. ODBC
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
Connection cn = DriverManager.getConnection( "jdbc:odbc:" + sDsn, sUsr, sPwd );
8.DB2
Class.forName("Com.ibm.db2.jdbc.net.DB2Driver");
String url="jdbc:db2://192.9.200.108:6789/SAMPLE"
cn = DriverManager.getConnection( url, sUsr, sPwd );
6.左图是 ResultSet的getXXX()方法,右图是SQL和Java的类型对应关系
7.获取数据库元数据
数据库元数据:数据库的相关信息
实例:
package v512.chap18;
import java.sql.*;
public class TestMetaData{
public static void main(String args[]){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:orcale";
conn = DriverManager.getConnection(url,"scott","tiger");
ResultSet rs = null;
DatabaseMetaData dmd = conn.getMetaData();
if (dmd == null) {
System.out.println ("No Meta available");
} else {
System.out.println ("数据库名称:" + dmd.getDatabaseProductName());
System.out.println ("数据库版本:" + dmd.getDatabaseProductVersion());
System.out.println ("数据库驱动程序:" + dmd.getDriverName());
System.out.println ("驱动程序版本号:" + dmd.getDriverVersion());
System.out.println ("并发访问的用户个数" + dmd.getMaxConnections());
System.out.println ("数据类型列表:" );
rs = dmd.getTypeInfo();
while(rs.next()){
System.out.println("\t" + rs.getString(1));
}
rs.close();
}
Statement stmt = conn.createStatement();
String s = "select * from dept";
rs = stmt.executeQuery(s);
System.out.println("数据表dept结构信息:");
ResultSetMetaData rsm = rs.getMetaData();
int columnCount = rsm.getColumnCount();
System.out.println("列序号\t列名\t数据类型");
for(int i=1;i<=columnCount;i++){
System.out.println(" " + i + " \t" +
rsm.getColumnName(i) + "\t" +
rsm.getColumnTypeName(i));
}
rs.close();
stmt.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null && !conn.isClosed()){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
返回的结果:
数据库名称:Oracle
数据库版本:Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
数据库驱动程序:Oracle JDBC driver
驱动程序版本号:11.2.0.1.0
并发访问的用户个数0
数据类型列表:
INTERVALDS
INTERVALYM
TIMESTAMP WITH LOCAL TIME ZONE
TIMESTAMP WITH TIME ZONE
NUMBER
NUMBER
NUMBER
LONG RAW
RAW
LONG
CHAR
NUMBER
NUMBER
NUMBER
FLOAT
REAL
VARCHAR2
DATE
DATE
TIMESTAMP
STRUCT
ARRAY
BLOB
CLOB
REF
数据表dept结构信息:
列序号 列名 数据类型
1 DEPTNO NUMBER
2 DNAME VARCHAR2
3 LOC VARCHAR2
8.访问SQL Server数据库
准备SQL Server数据库JDBC驱动程序
1. 从微软网站下载JDBC驱动程序安装文件
2. 本地安装该驱动程序包
3. 重新设置CLASSPATH环境变量
9.JDBC-ODBC编程
工作原理:
JDBC驱动程序管理器并不直接操纵数据库驱动程序,而是调用JDBC-ODBC 桥驱动程序操纵ODBC 驱动程序,进而连接各种类型的数据库。
JDBC驱动程序 -> JDBC-ODBC 桥驱动程序 -> ODBC 驱动程序 -> 各种类型的数据库 [可以结合上面的几幅图来理解]
可以封装很多的数据库或者数据文件:excel,access,SQL Server。。。
编程步骤:
第一步:创建ODBC数据源 (在Windows操作系统中把目标数据库封装成ODBC数据源)
找到 ODBC
配置好一个 ODBC 数据源
第二步:在程序中连接并操作ODBC数据源
package v512.chap18; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement; public class ODBCExample { public static void main(String[] args) {
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
Connection connection = DriverManager.getConnection("jdbc:odbc:MyExcelODBC1");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from [Sheet1$]");
while (resultSet.next()) {//注意,索引是从1开始的,否则报错:[Microsoft][ODBC 驱动程序管理器] 无效的描述器索引
System.out.println("name:"+resultSet.getString(1)+"---tel:"+resultSet.getString(2));
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Excel文件中的内容:
程序运行输出结果:
name:yinger---tel:15079576419.0
name:胡吉清---tel:13707950937.0
name:刘明---tel:13842879813.0
name:小熊强---tel:15244672815.0
name:朱思瑞---tel:13920137236.0
name:马继鸣---tel:13548607626.0
name:魏纪元---tel:13739068492.0
name:王晨龙---tel:13807493710.0
name:王沛东---tel:13875803565.0
name:杨阳---tel:13875810771.0
name:邹星乾---tel:13875960663.0
name:刘龙---tel:13875831389.0
name:易兵---tel:13875995083.0
name:张华敏---tel:13875972761.0
name:杨颖华---tel:13875953921.0
name:张丹羊---tel:15873116080.0
name:大哥---tel:13720254940.0
除了末尾多了个.0之外其他的数据都是没有问题的!
10.使用属性文件配置环境
将数据库连接信息(URL、用户名/密码等)保存到专门的属性文件中,而不在程序中直接给出
属性文件:
#Mysql db info
db_url = jdbc:mysql://localhost/blog
username = root
password = root
测试类:
package v512.chap18; import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties; public class JDBCExample { public static void main(String[] args) {
try {
Class.forName("org.gjt.mm.mysql.Driver");
// //直接编写得到连接
String url ="jdbc:mysql://localhost/blog";
// Connection connection = DriverManager.getConnection(url,"root","root"); //读取配置文件得到连接
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("E:\\mydb.properties");
properties.load(fileInputStream);
// String url = properties.getProperty("db_url");
System.out.println(url);
String username = properties.getProperty("username");
System.out.println(username);
String password = properties.getProperty("password");
System.out.println(password); Connection connection = DriverManager.getConnection(url,username,password); //进行数据查询
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select id,title from blog");
while (resultSet.next()) {
System.out.println(resultSet.getInt("id")+":"+resultSet.getString("title"));
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
jdbc:mysql://localhost/blog
root
root
1:I love Java
10:Java JSP
11:Java Servlet
12:Java Spring
14:cnblog
16:very good
17:500 tomcat
11.OCI方式访问Oracle
什么是OCI(Oracle Call Interface)方式?
OCI方式连接时Oracle客户端配置的三种方式:
1.使用Net Configuration Assistant
2.使用Net Manager图形化工具
3.直接修改数据库配置文件"tnsnames.ora" (我的电脑的路径:D:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN\tnsnames.ora)
12.可滚动/可更新结果集
结果集类型
不可滚动(FORWARD_ONLY)
滚动不敏感(SCROLL_INSENSITIVE):可以滚动,但是如果数据库中的数据发生了更改不会反映到结果集中
滚动敏感(SCROLL_SENSITIVE)
结果集的并发模式
只读的(READ_ONLY)
可更新的(UPDATABLE):允许对结果集进行更改,修改或者删除,并且可以将它反应到数据库中
Connection接口中提供的重载方法createStatement()用于获取可滚动/可更新结果集。
方法格式:Statement createStatement(int type, int concurrency)
注意:以上结果集的类型和并发模式受到具体的数据库和数据库驱动程序的限制
可以使用数据库元数据进行测试:
import java.sql.*;
public class TestMetaData{
public static void main(String args[]){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:orcale";
conn = DriverManager.getConnection(url,"scott","tiger");
ResultSet rs = null;
DatabaseMetaData dmd = conn.getMetaData();
if (dmd == null) {
System.out.println ("No Meta available");
} else {
System.out.println ("数据库名称:" + dmd.getDatabaseProductName());
System.out.println ("数据库版本:" + dmd.getDatabaseProductVersion());
System.out.println ("数据库驱动程序:" + dmd.getDriverName());
System.out.println ("驱动程序版本号:" + dmd.getDriverVersion());
System.out.println ("--------------------------------------------"); System.out.println ("结果集类型及支持情况(true-支持,false-不支持)");
System.out.println ("TYPE_FORWARD_ONLY: " +
dmd.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY));
System.out.println ("TYPE_SCROLL_INSENSITIVE: " +
dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));
System.out.println ("TYPE_SCROLL_SENSITIVE: " +
dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
System.out.println ("CONCUR_READ_ONLY: " +
dmd.supportsResultSetType(ResultSet.CONCUR_READ_ONLY));
System.out.println ("CONCUR_UPDATABLE: " +
dmd.supportsResultSetType(ResultSet.CONCUR_UPDATABLE));
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
使用可滚动结果集
(1)对于可滚动结果集,可以使用ResultSet 接口中定义的下述方法进行遍历:
boolean next()
boolean previous()
boolean first()
boolean last()
void beforeFirst():第一个的前面,在调用next就是第一个了
void afterLast():最后一个的后面
boolean relative(int rows):相对的移动一定的行数,负数是向前
boolean absolute(int row):绝对移动,移动到某一行
int getRow()
测试方法:
import java.sql.*;
public class TestScrollResultSet{
public static void main(String args[]){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery("select * from student"); while(rs.next()){
showOneRow(rs);
}
System.out.println("-----------");
rs.last();
showOneRow(rs);
rs.first();
showOneRow(rs);
rs.beforeFirst();
rs.next();
showOneRow(rs);
rs.absolute(2);
showOneRow(rs);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
} public static void showOneRow(ResultSet rs) throws SQLException{
System.out.print("第" + rs.getRow() + "行: ");
System.out.print(rs.getString(1));
System.out.print("\t" + rs.getString(2));
System.out.print("\t" + rs.getString(3));
System.out.println();
}
}
(2)对于可更新结果集,可以使用ResultSet 接口中定义的下述方法进行更新操作:
void updateXXX(String columnName, XXX x)
void updateXXX(int columnIndex, XXX x)
void updateRow():它必须紧跟在上面的方法之后
void moveToInsertRow():在当前的结果集中插入一行,相当于newRow,然后调用updateXXX()和insertRow方法就可以在数据库中插入一行数据
void insertRow()
void moveToCurrentRow():如果当前是在插入一行记录,调用这个方法可以将游标返回到刚才指向的行
void deleteRow()
void cancelRowUpdates()
测试方法:
import java.sql.*;
public class TestUpdatableResultSet{
public static void main(String args[]){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("select tid,name,salary from teacher");
//ResultSet rs = stmt.executeQuery("select teacher.* from teacher"); //更新前结果集中数据
while(rs.next()){
showOneRow(rs);
} //更新和删除记录
rs.beforeFirst();
while(rs.next()){
String name = rs.getString("name").trim();
if(name.equals("李四")){
double sal = rs.getDouble("salary");
rs.updateDouble("salary", sal + 8888);
rs.updateRow();
}else if(name.equals("张三")){
rs.deleteRow();
}
}
//插入新记录
rs.moveToInsertRow();
rs.updateInt("tid",1005);
rs.updateString("name","云飞扬");
rs.updateDouble("salary",2840);
rs.insertRow();
rs.close(); //结果集更新后后数据库中数据
System.out.println("--------------------------------------------");
rs = stmt.executeQuery("select * from teacher");
while(rs.next()){
showOneRow(rs);
}
rs.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
} public static void showOneRow(ResultSet rs) throws SQLException{
System.out.print("第" + rs.getRow() + "行: ");
System.out.print(rs.getInt(1));
System.out.print("\t" + rs.getString(2));
System.out.print("\t" + rs.getDouble(3));
System.out.println();
}
}
【注意】在实际的开发中并不建议在结果集中进行数据操作然后同步到数据库中
13.预处理语句 PreparedStatement
java.sql.PreparedStatement 接口提供了执行预编译SQL语句的功能,它继承了java.sql.Statement接口。
Connection对象的prepareStatement(String sql)方法可创建并返回PreparedStatement对象。
PreparedStatement接口主要方法:
void setXXX(int parameterIndex, XXX x)
ResultSet executeQuery()
int executeUpdate()
实例:
package v512.chap18; import java.sql.*; public class PrepStmt {
public static void main(String[] args) {
Connection con = null;
PreparedStatement pst = null;
try {
Class.forName("org.gjt.mm.mysql.Driver");
String url = "jdbc:mysql://localhost/blog";
con = DriverManager.getConnection(url, "root", "root");
String sql = "insert into blog(categoryid,title,content,created_time) values(?,?,?,?)";
pst = con.prepareStatement(sql);
pst.setInt(1, 1);
pst.setString(2, "Java vs C#");
pst.setString(3, "Java is better than C#");
pst.setDate(4, new Date(2010, 8, 8));
pst.executeUpdate(); System.out.println("id\ttitle\tcreateTime");
pst = con.prepareStatement("select id,title,created_time from blog where id = ?");
pst.setInt(1, 1);
ResultSet rs = pst.executeQuery();
if (rs.next()) {
System.out.println(rs.getInt(1) + "\t" + rs.getString(2).trim() + "\t" + rs.getDate(3));
} } catch (Exception e) {
System.err.println(e);
} finally {
try {
if (pst != null) {
pst.close();
}
} catch (Exception e) {
e.printStackTrace();
} try {
if (con != null) {
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
输出结果:
id title createTime
1 I love Java 2011-05-11
数据库中也有相应的数据被插入了,只是程序的设值不合理。。。
14.调用存储过程
java.sql.CallableStatement接口提供了调用数据库服务器端存储过程(Procedure)的功能,它继承了java.sql. PreparedStatement接口。
Connection 对象的prepareCall(String sql) 方法可创建并返回CallableStatement对象。
CallableStatement接口主要方法:
void setXXX(int parameterIndex, XXX x)
boolean execute()
采用存储过程可以提高系统的运行效率,但是在数据库移植的时候会产生一些错误或者加重移植的操作任务
实例:
首先建立一个存储过程:
drop procedure MyProcedure;
drop table person;
create table person(id number primary key, name char(20), age number);
create or replace procedure MyProcedure (pid in number,name in char,age in char)
as
begin
insert into person values(pid,name,age);
end;
/
测试类:
import java.sql.*;
public class CallStmt{
public static void main(String[] args){
Connection con = null;
CallableStatement cst = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
con = DriverManager.getConnection(url,"scott","tiger");
cst = con.prepareCall("{call MyProcedure(?,?,?)}");
cst.setInt(1,1001);
cst.setString(2,"Jenny");
cst.setInt(3,48);
cst.execute();
cst.close();
}catch(Exception e){
System.err.println(e);
}finally{
try{
if(con != null){
con.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
15.事务处理
(1)和数据库中的事务管理模式相对应,JDBC 中的Connection对象也可分为自动提交和非自动提交两种模式。
JDBC驱动程序的默认事务管理模式为"自动提交"。
Connection接口提供的事务处理相关方法:
void setAutoCommit(boolean autoCommit):默认是true
boolean getAutoCommit():得到当前的提交方式
void commit():commit和rollback是在关闭了自动提交时才会有的方法
void rollback()
测试实例:
import java.sql.*; public class TestCommit{
public static void main(String args[]){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url="jdbc:oracle:thin:@127.0.0.1:1521:ora9";
conn=DriverManager.getConnection(url,"scott","tiger");
boolean autoCommit = conn.getAutoCommit(); // 关闭自动提交功能
conn.setAutoCommit(false);
Statement stmt=conn.createStatement();
stmt.executeUpdate("insert into dept values (77,'Market','Beijing')");
stmt.executeUpdate("insert into dept values (88,'R&D','Shanghai')");
ResultSet rs=stmt.executeQuery("select * from dept");
while(rs.next()){
System.out.print("DeptNo: "+rs.getInt(1));
System.out.print("\tDeptName: "+rs.getString(2));
System.out.println("\tLOC: "+rs.getString(3));
}
// 提交事务
conn.commit();
// 恢复原来的提交模式
conn.setAutoCommit(autoCommit);
stmt.close();
}catch(Exception e){
System.out.println("操作失败、任务撤消!");
try{
// 回滚、取消前述操作
conn.rollback();
}catch(Exception e1){
e.printStackTrace();
}
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
(2)事务处理之部分回滚
JDBC3.0 开 始 支 持 在 事 务 中 使 用 保 存 点(Savepoint),以实现对数据库事务的进一步控制、即支持部分回滚功能。
java.sql.Savepoint接口表示数据库事务中的保存点。
在Connection对象的rollback()方法中可以对当前事中的保存点进行引用,从而将事务回滚到该保存点。
在保存点之前的更新操作能生效,但是之后的更新不生效。
代码实例:
import java.sql.*;
public class TestSavepoint{
public static void main(String[] args){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("insert into teacher values(11,'Tom',2500)");
stmt.executeUpdate("insert into teacher values(12,'John',3400)");
Savepoint sp1 = conn.setSavepoint("p1");
stmt.executeUpdate("insert into teacher values(13,'Billy',3150)");
Savepoint sp2 = conn.setSavepoint("p2");
stmt.executeUpdate("update teacher set salary = salary+8888 where tid = 12");
ResultSet rs = stmt.executeQuery("select avg(salary) from teacher");
rs.next();
double avg_sal = rs.getDouble(1);
if(avg_sal > 4000){
conn.rollback(sp1);
}else if(avg_sal >= 3000){
conn.rollback(sp2);
}
conn.commit(); rs = stmt.executeQuery("select * from teacher");
while(rs.next()){
System.out.println(rs.getInt(1) + "\t" + rs.getString(2).trim() + "\t" + rs.getDouble(3));
}
rs.close();
stmt.close();
}catch(Exception e){
System.out.println("Failure,rollback!");
try{
conn.rollback();
}catch(Exception e1){
e.printStackTrace();
}
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
16.批处理
JDBC2.0 开 始 提 供 了 对 数 据 库 操 作 的 批 处 理(Batch Processing)功能,使用批处理功能避免了向数据库进行一连串的调用,
从而可以显著提高程序的运行效率。
Statement接口提供的批处理相关方法:
void addBatch(String sql)
int[] executeBatch()
void clearBatch()
实例代码:
import java.sql.*;
public class TestBatch{
public static void main(String[] args){
Connection conn = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.addBatch("insert into teacher values(11,'Tom',2500)");
stmt.addBatch("insert into teacher values(12,'John',3400)");
stmt.addBatch("insert into teacher values(13,'Billy',3150)");
stmt.addBatch("update teacher set salary = salary + 88");
stmt.executeBatch();
conn.commit(); ResultSet rs = stmt.executeQuery("select * from teacher");
while(rs.next()){
System.out.println(rs.getInt(1) + "\t" + rs.getString(2).trim() + "\t" + rs.getDouble(3));
}
rs.close();
stmt.close();
}catch(Exception e){
System.out.println("Failure,rollback!");
try{
conn.rollback();
}catch(Exception e1){
e.printStackTrace();
}
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
17.高级SQL类型 BLOB/CLOB
BLOB(Binary Large OBject,二进制大对象)类型用于保存大规模的二进制数据
CLOB(Character Large OBject,文本大对象)类型则用于保存大规模的文本数据
JDBC2.0开始引入了对应于SQL99标准的多种高级数据类型,其中最重要的是两种大对象类型BLOB和CLOB
要在Oracle数据库中使用这两种大对象类型必须要使用高版本的数据库驱动程序
测试实例:
保存Blob
import java.sql.*;
import java.io.*; public class SavePicture{
public static void main(String[] args){
Connection conn = null;
PreparedStatement stmt = null;
FileInputStream fis = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url, "scott","tiger");
String sql = "insert into Student_List values(?,?,?)";
stmt=conn.prepareStatement(sql);
stmt.setString(1,"s01");
stmt.setString(2,"Youyou");
File file = new File("yy.jpg");
fis = new FileInputStream(file);
stmt.setBinaryStream(3, fis, (int)file.length());
stmt.executeUpdate();
stmt.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(fis!=null){
fis.close();
}
}catch(IOException ioe){
ioe.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
得到BLOB
import java.sql.*;
import java.io.*; public class GetPicture{
public static void main(String[] args){
PreparedStatement stmt = null;
ResultSet rs = null;
Connection conn = null;
FileOutputStream fos = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url= "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
String sql="select * from Student_List where Student_ID='s01'";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
rs.next();
File file = new File("d:\\kk.jpg");
fos = new FileOutputStream(file);
InputStream is = rs.getBinaryStream(3);
int len = 0;
byte b[] = new byte[4*1024];
while((len=is.read(b))!=-1)
{
fos.write(b,0,len);
}
fos.flush();
fos.close();
is.close();
rs.close();
stmt.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(fos!=null){
fos.close();
}
}catch(IOException ioe){
ioe.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
保存CLOB
import java.sql.*;
import java.io.*; public class SaveClob{
public static void main(String[] args){
Connection conn = null;
PreparedStatement stmt = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url, "scott","tiger");
String sql = "insert into book_list values(?,?,?)";
stmt=conn.prepareStatement(sql);
stmt.setString(1,"b001");
stmt.setString(2,"99个简单法则");
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
StringBuffer sb = new StringBuffer();
String s;
while((s=br.readLine()) != null){
sb.append(s + "\n");
}
br.close();
String content = sb.toString();
StringReader sr = new StringReader(content);
stmt.setCharacterStream(3, sr, content.length());
stmt.executeUpdate();
sr.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
得到CLOB
import java.sql.*;
import java.io.*; public class GetClob{
public static void main(String[] args){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
FileOutputStream fos = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url= "jdbc:oracle:thin:@localhost:1521:ora9";
conn = DriverManager.getConnection(url,"scott","tiger");
String sql="select * from book_list where bid='b001'";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
rs.next(); StringBuffer sb = new StringBuffer();
Reader rd = rs.getCharacterStream(3);
BufferedReader br = new BufferedReader(rd);
String s;
while((s=br.readLine())!=null)
{
sb.append(s + "\n");
}
System.out.println(sb.toString()); rs.close();
br.close();
stmt.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
JavaEE之JDBC编程[详解]的更多相关文章
- Log4J:Log4J三大组件:Logger+Appender+Layout 格式化编程详解
快速了解Log4J Log4J的三个组件: Logger:日志记录器,负责收集处理日志记录 (如何处理日志) Appender:日志输出目的地,负责日志的输出 (输出到什么 地方) Layo ...
- ORACLE PL/SQL编程详解
ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设 ...
- Linux串口编程详解(转)
串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...
- [强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)
原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天 ...
- [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)
原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ...
- 【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航
原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人 ...
- [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)
原文:[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) [推荐]ORACLE PL/SQL编程详解之一: PL/SQL 程序设计简介(千里之行,始于足下 ...
- [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)
原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日 ...
- Java的JDBC事务详解
Java的JDBC事务详解 分类: Hibernate 2010-06-02 10:04 12298人阅读 评论(9) ...
随机推荐
- 接口由40秒到200ms优化记录
场景还原 一个业务逻辑较为复杂的业务,涉及到n次遍历,其中有循环查询/更新数据库,事务的管理,加上一些业务逻辑的计算.最初的接口,纯粹按照产品提供的相关业务逻辑,单纯的编码,耗时较长,近40秒的处理时 ...
- BZOJ3291Alice与能源计划——匈牙利算法+模拟费用流
题目描述 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验.为 了方便,我们可以将火星抽象成平面,并建立平面直角坐标系.火星上一共有N个居民点 ...
- Docker最全教程
摘自雪雁大佬的博客,地址:https://www.cnblogs.com/codelove/default.html 目录: Docker最全教程——从理论到实战(一) Docker最全教程——从理论 ...
- Android环境搭建(大学授课课件)
前面一直没有提过如何搭建Android开发环境,其实这些网上一大堆,随便一搜就是很多大神的详细介绍.本人过于懒惰,拿出大学授课课件供大家参考.非原创 位) 下载地址: sdk:http://pan ...
- [APIO 2009] Atm
传送门:>Here< 题意:给出一个有向图(有环),每个点有点权.从点S出发,经过每个点Tot可以加上点权,点可以经过多次,然而点权不能重复加多次.先要求走到某个终点E时点权最大.先要求在 ...
- 洛谷AT2046 Namori(思维,基环树,树形DP)
洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...
- CentOS 7 Shell脚本编程第九讲 read命令简单介绍
测试代码 sqlSessionFactory.openSession(false).getMapper(StudentMapper.class).findStudentById(id)核心方法:org ...
- 05 Zabbix4.0触发器表达式Trigger expression支持的函数
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 05 Zabbix4.0触发器表达式Trigger expression支持的函数 所有函数返回值 ...
- 觉得一篇讲SPFA还不错的文章
我觉得他整理的有一些乱,我都改成插入代码了,看的顺眼一些 转载自http://blog.csdn.net/juststeps/article/details/8772755 下面的都是原文: 最短路径 ...
- Win10 安装 Linux子系统 Ubuntu18.04 / Kali Linux 的体验
汇总系列:https://www.cnblogs.com/dunitian/p/4822808.html#linux 几年前就看到新闻,今天周末,突发奇想,家里电脑安装下子系统不就不用安装开发的那些环 ...