第20章 数据库编程

通过本章需要理解JDBC的核心设计思想以及4种数据库访问机制,理解数据库连接处理流程,并且可以使用JDBC进行Oracle数据库的连接,理解工厂设计模式在JDBC中的应用,清楚地理解DriverManager类的作用,掌握Connection、PreparedStatement、Result等核心接口的使用,柄可以实现数据的增、删、改、查操作,掌握JDBC提供的提供的数据批处理操作的实现,掌握数据库事物的作用并可以利用JDBC实现数据库是控制。

在现代的程序开发中,大量的开发都是基于数据库尔德,是用数据库可以方便的实现数据的存储及查找,本章将就Java的数据库操作技术--JDBC进行讲解。

20.1 JDBC简介

JDBC(Java Database Connectivity,Java数据库连接)提供了一个与平台无关的,用于执行SQL语句的标准Java API,可以方便的实现多中国关系型数据库的统一操作,他有一组用Java语言编写的类和接口组成。不同的数据库如果想要使用Java开发,就必须实现这些接口的标准。但是JDBC严格来说不属于技术,而是一种服务,即所有的操作步骤完全固定。

提示:如果要学习本章,首先要具备基本的SQL语法知识,同时本书使用的是Oracle数据库,可以参照《Oracle开发实战经典》

JDBC本身提供的是一套数据库操作标准,而这些标准有需要各个数据库厂商实现,所以针对每个数据库厂商都会提供一个JDBC的驱动程序。目前就比较常见的JDBC驱动程序可以分为以下四类

1 JDBC-ODBC桥驱动

JDBC-ODBC是SUN提供的一个标准JDBC操作,直接利用微软的ODBC进行数据库的连接操作,其桥接模式如图

但是由于此种模式需要通过JDBC访问ODBC,再通过SQL数据库访问SQL数据库,所以在数据量较大时,这种操作性能较低,所以在通常情况下不推荐使用这种方式进行操作。
提示:关于ODBC
ODBC(Open Database Connectivity开发数据库连接)是微软公司提供的一套数据库操作的编程接口,SUN的JDBC实现实际上也是模仿了ODBC的设计。

2 JDBC本地驱动

直接使用各个数据库生产上升提供的程序库操作,但是由于其智能应用在特定的数据库上,会丧失程序的可移植性,与JDBC-ODBC桥接模式相比较,此类操作模式的性能较高,但其最大的缺点在于无法进行网络分布式存储

3JDBC网络驱动

这种驱动程序将JDBC转换为与DBMS无关的网络协议,之后这种协议又被某台服务器转换为一种DBMS协议。这种网络服务器中间件能够将它的纯java客户机链接到多种不同的数据库上,如下所示,所用的具体协议取决于提供者,JDBC网络驱动是最为灵活的JDBC驱动程序

4 本地协议纯JDBC驱动

这种类型的驱动程序将JDBC调用直接转换为DBMS所使用的网络协议。这将允许从客户机上直接调用DBMS服务器,是Internet访问的一个很实用的解决方法。
        JDBC中的·核心组成在java.sql包中定义,该包中的核心类结构为DriverManager类,Connection接口、Statement接口、PreparedStatement接口、ResultSet接口

20.2 连接Oracle数据库

oracle数据库安装(全步骤详解) - 知乎

JDBC可以通过标准连接支持JDBC的SQL数据库,本节将利用JDBC实现Oracle数据库的连接。数据库的连接操作主要是用DriverManager.getConnection()方法完成,此类可以获取多个数据库的连接,每一个数据库链接都是用Connectio接口描述,方法如下
oracle数据库安装(全步骤详解) - 知乎

提示:JDBC连接准备
在通过JDBC连接SQL数据库首先必须保证连接的SQL数据库的服务进程已经开启,例如本次链接的事Oracle数据库,必须开启监听与数据库实例服务JDBC属于Java提供的服务标准,对于所有的服务都有着固定的操作步骤。JDBC操作步骤如下
(1)加载数据库驱动程序。各个数据库都会提供JDBC的驱动程序开发包,直接把JDBC操作所需要的开发包(一般为*.jar或*.zip)配置到CLASSPATH路径即可。
        提示:Oracle驱动程序路径
一般像Oracle或DB2这种大型数据库,在安装后在安装目录中都会提供数据库厂商提供的相应数据库驱动程序,开发者需要将驱动程序设置到CLASSPATH中(如果是Eclipse,则需要通过Java Builder Path配置扩展*.jar文件).

(2)连接数据库 根据不同数据库提供的连接信息、用户名与密码建立数据库连接通道。
Oracle连接地址结构:jdbc:oracle:thin:@主机名称:端口号:SID.例如连接本机MLDN数据库:
jdbc:oracle:thin@localhost:1521:mldn;
用户名:scott
密码:tiger
(3)使用语句进行数据库操作。数据库操作分为更新和查询两种操作,除了可以使用标准的SQL语句外,对于各个数据库也可以使用其自己提供的各种命令。
(4)关闭数据库连接。数据库操作完毕后需要关闭连接以释放资源。

范例:连接Oracle数据库

package cn.mldn.demo;
import java.sql.Connection;
import java.sql.DriverManager;
public class JDBCDemo
{
private static final String DATABASE_DRIVER="oracle.jdbc.driver.OracleDriver";
private static final String DATABASE_URL="jdbc:oracle:thin:@localhost:1521";
private static final String DATABASE_USER="scott";
private static final String DATABASE_PASSWORD="tiger";
public static void main(String[]args)throws Exception
{
Connection conn=null;//保存数据库的连接
Class.forName(DATABASE_DRIVER);//加载数据库驱动程序
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);
System.out.println(conn);
conn.close();
}
}

本程序将数据库连接的相关信息定义为常量,随后进行数据库驱动程序加载,加载成功后会根据连接地址、用户名、密码获取连接。由于本程序已经连接成功,所以输出得conn对象不为null,数据库连接属于资源,所以在最后需要使用close()方法进行关闭。

提示:JDBC使用了工厂模式
在JDBC开发中Connection是一个数据库连接的标准接口,而程序要想获取Connection接口实例,则必须通过DriverManager类获取 通过上图可以发现,程序通过DriverManager类可以在不清楚子类具体实现的情况下获取任意数据库的Connection接口实例,所以DriverManager类的作用相当于工厂类。

20.3 Statement数据操作接口

Statement是JDBC中提供的数据库操作接口,利用其可以实现数据的更新与查询的处理操作。该接口定义如下:
        public interface Statement extends Wrapper,AutoCloseable{}
开发者可以通过Connection接口提供的createStatement()方法创建Statement接口实例,随后利用下表的接口进行SQL数据操作
下面将通过Statement实现数据表的增加、修改、删除、查询等常见操作,本次所使用的数据表创建脚本如下:
范例:数据库创建脚本
DROP TABLE news PURGE;
DROP SEQUENCE news_seq;
CREATE SEQUENCE news_seq;
CREATE TABLE news(nid Number,title VARCHAR(30),read NUMBER,price NUMBER,content CLOB,pubdate DATE,CONSTRAINT pk_nid PRIMARY KEY(nid));
在给定的数据库脚本中包含数据库开发中的常见数据类型(NUMBER,VARCHAR2,DATE,CLOB),且使用序列(SEQUENCE进行nid列数据生成).

20.3.1 数据更新操作

        在SQL语句中数据的更新操作一共分为三种:增加(INSERT)、修改(UPDATE)、删除(DELETE).Statement接口的最大特点是可以直接执行一个标准的SQL语句

范例:实现数据增加
SQL语法:INSERT INTO 表名称(字段,字段,...)values(值,值)
package cn.mldn.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo
{
private static final String DATABASE_DRIVER="oracle.jdbc.driver.OracleDriver";
private static final String DATABASE_URL="jdbc:oracle:thin:@localhost:1521";
private static final String DATABASE_USER="scott";
private static final String DATABASE_PASSWORD="tiger";
public static void main(String[]args)throws Exception
{
String sql="INSERT INTO news(nid,title,price,content,pubdate)"+"values(news_seq.nextval,"aaa",10,9.15,"+
+" '啊啊啊啊',"
"TO-DATE('2015-02-17','yyyy-mm-dd'))"//SQL语句
Connection conn=null;//保存数据库的连接
Class.forName(DATABASE_DRIVER);//加载数据库驱动程序
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);
Statement stmt=conn.createStatement();//数据库操作对象
int count=stmt.executeUpdate(sql);//返回更新操作数
System.out.println("更新操作的数据行数"+count);//输出数据行数
conn.close();
}
}

本程序通过Connection连接对象创建了Statement接口实例,这样就可以利用executeUpdate()方法直接执行SQL更新语句,当执行完成后会返回更新的数据行数,由于只增加一行数据,所以最终取得更新行数为1.

范例:实现数据修改
SQL语法:UPDATE 表名称 SET 字段 字段=值,...WHERE 更新条件;
public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
String sql="UPDATE news set title='aaaa',content='BBB',"
+"read=999 WHERE nid=5";
}
}

范例:实现数据删除
SQL语法:DELETE FROM 表名称 WHERE 删除条件(s)
DELETE FROM news WHERE nid IN (11,13,15)

20.3.2 数据查询操作

数据查询操作会利用SQL语句向数据库发出SELECT查询指令,而查询的结果如果要返回给程序进行处理,就必须通过ResultSet接口进行封装。ResultSet是一种可以保存任意查询结果的集合结构,所有查询结果会通过ResultSet在内存中形成一张虚拟表,而后开发者可以根据数据行的缩影,按照数据类型获得列数据内容,其处理流程如下

当所有的记录返回到ResultSet的时候,所有的内容都是按照表结构的形式存放的,所以用于只需要按照数据类型从每行取出所需要的数据即可

范例:实现数据查询

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
//此处编写的        SQL语句,明确写明了要查询的列名称,这样查询结果就可以根据列索引顺序获取内容。
String sql="SELECT nid,title,read,price,content,pubdate FROM news";
Connection conn=null;//保存数据库连接
Class.forName(DATABASE_DRIVER);//加载数据库驱动程序
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);//连接数据库
Statement stmt=conn.createStatement();//数据库操作对象
ResultSet rs=stmt.executeQuery(sql);//执行查询
while(rs.next())
{
//循环获取结果集数据
int nid=rs.getInt(1);//获取第一个查询列结果
String title=rs.getString(2);//第二个
int read=rs.getInt(3);//第3个
double price=rs.getDouble(4);
String content=rs.getString(5);
Date pubdate=rs.getDate(6);
}
}
}

本程序通过ResultSet集合保存了JDBC查询结果,由于ResultSet以表的形式返回,所以可以利用next()方法修改数据索引(同时也可以判断数据行是否全部读取完毕),随后利用getXxx()方法获取数据列类型读取数据内容。

提问:SQL使用“*”查询不是更方便
在本程序中编写SQL查询语句,使用“*”不是更方便吗
String sql="SELECT *FROM news";
为什么在本程序中不使用*通配符,而写上具体列的名称呢

回答:使用具体列名称的查询更加适合于程序维护
在本程序中,如果在查询语句上使用了"*",那么在使用ResultSet依据索引获得内容时就必须根据查询列的默认顺序进行定义,这样势必会造成代码的开发与维护的困难。在这种情况下为了可以清晰地读取数据,就需要明确的使用列名称进行数据读取
String sql="SELECT *FROM news";
while(rs.next())
{
//循环获取结果集数据
int nid=rs.getInt(1);//获取第一个查询列结果
String title=rs.getString(2);//第二个
int read=rs.getInt(3);//第3个
double price=rs.getDouble(4);
String content=rs.getString(5);
Date pubdate=rs.getDate(6);
}
虽然以上代码可以实现读取,但是也需要注意内存占用的问题:数据查询时如果返回了过多的无用数据,会造成内存占用,导致性能下降,所以在使用JDBC进行数据查询时最好只查询需要的数据内容。

20.4 PreparedStatement数据操作接口

PreparedStatement是Statement的子接口,属于SQL预处理操作,与直接使用Statement不同的是,PreparedStatement在操作时,是先在数据表中准备好了一条待执行的SQL语句,随后在设置具体的内容,这样的处理模型使得数据库操作更加安全,为了解释PreparedStatement的作用,下面首先通过Statement模拟一个数据增加操作。

范例:观察Statement接口使用问题

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
String title="mldn";
int read=99;
double price=99.8;
String content="AAA";
String pubdate="2017-09-15";
String sql="INSERT INTO news(nid,title,read,price,content,pubdate) VALUES"
+"(news seq.nextval,'"+title
+"',"+read+","+price+","+"'"+content
+"', TO DATE('"+pubdate+"',','yyyy-mm-dd'))";//拼凑执行SQL
System.out.println(sql);//输出拼凑后的SQL
Connection conn=null;//保存数据库连接
Class.forName(DATABASE_DRIVER);//加载数据库连接
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);//连接数据库
Statement stmt=conn.createSatement();//数据库操作对象
int count=stmt.executeUpdate(sql);//返回更新数据行数
System.out.println(""+count);
conn.close();

}
}

本程序通过变量的形式定义了SQL要插入的数据内容,而通过本程序的执行可以发现statement有如下三个问题
Statement在数据库操作中需要一个完整的SQL明玲玲,一旦需要通过变量进行内容接收,则需要进行SQL语句的拼接,而这样的代码不方便阅读也不方便维护,执行的SQL语句中如果出现一些限定符号,则拼凑SQL执行时就会引发SQL标记异常。
进行日期数据定义时只能够使用String类型,而后通过数据库函数转换。
综合以上几个问题,就可以得出结论,Statement接口只适用于简单执行SQL语句的情况,而要想更加安全可靠的进行数据库操作,就必须通过PreparedStatement接口完成。

20.4.1PreparedStatement数据更新

在PreparedStatement进行数据库操作时,可以再便携SQL语句时通过“?”占位符的设计,Connection接口会根据磁SQL语句通过preparedStatement()方法实例化PreparedStatement接口实例(此时并不是到具体数据内容,在进行更新或查询擦左前利用setXxx()方法依据设置的占位符所言顺醋进行内容设置。常用方法如下

范例:使用PreparedStatement接口实现数据增加操作

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
String title="mldn";
int read=99;
double price=99.8;
String content="AAA";
java.util.Date pubdate=new java.util.Date();//定义日期对象
//需要先定义SQL语句后才可以创建PreparedStatement接口实例,定义时可以采用占位符
String sql="INSERT INTO news(nid,title,read,price,content,pubdate) VALUES"+
"(news_seq.nextval,?,?,?,?,?)";使用?作为占位符
Connection conn=null;//保存数据库连接
Class.forName(DATABASE_DRIVER);//家在数据库驱动程序
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);//连接数据库
pstmt.setString(1,title);//设置索引内容
pstmt.setInt(2,read);//设置索引内容
pstmt.setDouble(3,price);
pstmt.setString(4,content);
pstmt.setDate(5,new java.sql.Date(pubdate.getTime()));
int count=pstmt.executeUpdate();//返回影响的行数
System.out.println("更新操作影响的数据行数:"+count);
conn.close();
}
}

本程序在定义SQL语句的时候使用若干个“?”进行要操作数据的占位符定义,这样在执行更新前就必须利用setXxx()方法根据索引和列类型进行数据内容的设置,由于此类方式没有采用拼凑式的SQL定义,所以程序编写简介,数据的处理更加安全,程序开发也更加灵活。

本程序在定义SQL语句的时候使用若干个"?"进行要操作数据的占位符定义,这样在执行更新前就必须利用setXxx()方法依据索引和列类型进行数据内容的设置,由于此类方法没有采用拼凑式的SQL定义,所以程序编写简洁,数据的处理更加安全,程序的开发也更加灵活。

提示:关于日期时间型数据在JDBC中的描述

在本程序中使用setDate()方法设置日期数据时执行了以下的代码pstmt.setDate(5,new java.sql.Date(pubdate.getTime()));
        此代码的核心意义在于将java.util.Date类的实例转化为了java.sql.Date类的实例,之所以这样转换是因为在JDBC中PreparedStatement、ResultSet操作的日期类型为java.sql.Date

由于JDBC并没有与java.util.Date类产生任何直接关联,所以在使用PreparedStatement进行内容设置时就需要将java.util.Date的时间错数据去除,并使用java.sql.Date、java.sql.Time、java.sql.Timestamp的构造方法将时间戳变为各自的子类实例化才可以通过setXxx()方法设置。而在使用ResultSet获取数据时,所有的日期时间类实例都可以自动向上转型为java.util.Date类实例

20.4.2 PreparedStatement数据查询

查询是在实际开发中最复杂也是项目中使用最多的数据库操作,利用PreparedStatement也可以通过占位符实现数据查询操作。

范例:查询表中全部数据

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
String sql="SELECT nid,title,read,price,content,pubdate FROM news";
Connection conn=null;//保存数据库连接
Class.forName(DATABASE_DRIVER);//加载数据库驱动程序
conn=DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD        );//连接数据库
PreparedStatement pstmt=conn.preparedStatement(sql);
ResultSet rs=pstmt.executeQuery();//执行查询
while(rs.next())
{
int nid=rs.getInt(1);
String title=rs.getString(2);
int read=rs.getInt(3);
double price=rs.getDouble(4);
String content=rs.getString(5);
Date pubdate=rs.getDate(6);
}
}
}

本程序对news数据表数据实现了简单查询,由于查询SQL语句中并没有使用?占位符设计,所以可以直接使用executeQuery()方法执行查询。

范例:根据id进行查询

public class JDBCDemo
{
public static void main(String []args)throws Exception
{
String sql="SELECT nid,title,read,price,content,pubdate FROM news WHERE nid=?";
PreparesStatement pstmt=conn.prepareStatement(sql);//数据库的操作对象
pstmt.setInt(1,5);//设置nid的数据
ResultSet rs=pstmt.executeQuery();//执行查询
if(rs.next())
{}
conn.close();
}
}

本程序查询了指定编号的新闻数据,在定义SQL查询语句时使用了限定符进行查询条件数据设置。由于此类查询最多只会返回1行数据,所以在使用ResultSet获取数据时利用if语句对查询结果进行判断,如果查询结果存在,则进行输出。

范例:实现数据模糊查询同时进行分页控制

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
int currentPage=2;//当前页
int lineSize=5;//每页显示的数据行
String column="title";
String keyWord="mldn";
String sql="SELECT * FROM (SELECT nid,title,read,price,content,pubdate,ROWNUM rn FROM news WHERE "+column+" LIKE ? AND ROWNUM<=? ORDER BY nid)temp WHERE temp.rn>?";
PreparedStatement pstmt=conn.prepareStatement(sql);//数据库的操作对象
pstmt.sednString(1,"%"+keyWord+"%");//设置占位符数据
pstmt.setInt(2,currentPage*linSize);//设置占位符数据
pstmt.setInt(3,(currentPage-1)*lineSize);//设置占位符数据
ResultSet rs=pstmt.executeQuery();
while(rs.next())
{}
conn.close();


}
}
本程序实现了一个开发中最为重要的数据分页模糊查询操作,将利用Oracle数据库提供的分页语法实现指定数据列上的数据模糊匹配,由于匹配的数据可能出现在数据的任意匹配位置上,所以在设置查询关键字时使用"%%"匹配符

注意:不要在列名称上使用占位符

在使用PreparedStatement进行占位符定义式只允许在列内容上使用,儿不允许在列名称上使用。以本程序为例"FROM news WHERE ? LIKE ? AND ROWNUM<=? PRDER BY nid"在SQL语句中限定查询的语法需要通过列名称匹配内容,如果此时将列名称也设置为?.则代码执行时将出现错误。

范例:数据统计查询

public class JDBCDemo
{
public static void main(String []args)throws Exception
{
String column="title";
String keyWord="mldn";
String sql="SELECT COUNT(*) FROM news WHERE"+column+"LIKE ?";
PreparedStatement pstmt=conn.preparedStatement(sql);//数据库的操作对象

pstmt.setString(1,"%"+keyWord+"%");//设置占位符数据
ResultSet rs=pstmt.executeQuery();//执行查询
if(rs.next())
{
long count=rs.getLong(1);
System.out.println(""+count);
}
}
}

在SQL查询中使用COUNT(*)方法可以实现指定数据表中的数据统计,并且不管表中是否有数据行都一定会返回COUNT()函数的统计查询结果,即rs.next()方法判断的结果一定为true,在进行数据统计时,由于表中数据行较多,往往会通过getLong()方法接收统计结果。

20.5 数据批处理

JDBC随着JDK每次版本的更新也在不断地完善。从JDBC2.0开始为了方便操作者进行数据库的开发提供了许多更加方便的操作,包括可滚定的结果集、使用结果集更新数据、批处理,其中批处理在开发中使用较多

范例:使用Statement实现批处理

public class JDBCDemo
{
public static void main(String[]args)throws Exception
{
Statement stmt=conn.createStatement();//创建数据库的操作对象
stmt.addBatch("INSERT INTO news (nid,title)VALUES (news_seq.nextval,'MLDN-A')");
stmt.addBatch("INSERT INTO news (nid,title)VALUES (news_seq.nextval,'MLDN-B')");
stmt.addBatch("INSERT INTO news (nid,title)VALUES (news_seq.nextval,'MLDN-C')");
stmt.addBatch("INSERT INTO news (nid,title)VALUES (news_seq.nextval,'MLDN-D')");
int result[]=stmt.executeBatch();

}
}

本程序通过Statement提供的addBatch()方法加入了5条数据更新语句,这样当执行executeBatch()方法时会一次性提交多条更新指令,并且所有更新语句影响的数据行数将通过数组返回给调用处,此类操作在大规模数据更新时会提高处理性能。

范例:使用PreparedStatement执行批处理

public static void main(String[]args)throws Exception
{
String sql="INSERT INTO news(nid,title) VALUES(news_seq.nextval,?)";
String title[]=new String[]{"A","B","C","D"};
PreparedStatement pstmt=conn.prepareStatement(sql);//创建数据库的操作对象
for(String title:titles)
{
pstmt.setString(1,title);//设置占位符数据
pstmt.addBatch();//追加批处理
}
int result[]=pstmt.executeBatch();
}

20.6 事务控制

事务处理在数据库开发中有着非常重要的作用,所谓的事务,就是所有的操作要么一起成功,要么一起失败。事务本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)、持久性(Durability)4个特征,又称ACID特征

原子性:原子性时事务最小的单元,是不可再分的单元,相当于一个个小的数据库操作,这些操作必须同时完成,如果有一个失败,则一切操作将全部失败如上图所示,用户A转账和用户B转账分别是两个不可再分的操作,但是如果用户A的转账失败,则用户B的转账操作也肯定无法成功。
一致性:是指在数据库操作的前后是完全一致的,保证数据的有效性,如果事务正常操作则系统会维持有效性,如果事务出现了错误,则回到最原始状态,也要维持其有效性,这样保证事务开始和结束时系统处于一致状态,如上图,如果用户A和用户B转账成功,则保持其一致性,如果现在A和B转账失败,则保持操作之前的一致性,即用户A的钱不会减少,用户B的钱不会增加。
隔离性:多个事务可以同时进行且彼此之间无法访问,只有当事务完成最终操作的时候,才可以看到结果。
持久性:当一个系统崩溃时,一个事物依然可以坚持提交,当一个事务完成后,操作的结果保存在磁盘中,永远不会被回滚,如上图所示,所有的资金数都保存在磁盘中,所以即使系统发生了错误,用户的资金也不会减少。

在JDBC中事务控制需要通过Connection接口中提供的方法来实现,由于JDBC中已经默认开启了事物的自动化提交模式,所以为了保证事务处理的一致性,就必须调用setAutoCommit()方法取消事务自动提交,随后再根据SQL的执行结果来决定实物是否需要提交(commit()或回滚(rollback()))

范例:使用JDBC实现事务控制(利用Statement批处理进行演示)

public static void main(String[]args)throws Exception
{
Connection conn=null;//保存数据库连接
Class.forName(DATABASE_DRIVER);//加载数据库驱动程序
conn.DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);//连接数据库
Statement stmt=conn.createStatement();//创建数据库的操作对象
stmt.addBatch("INSERT INTO news(nid,title)VALUES(news_seq.nextval,'B')");
stmt.addBatch("INSERT INTO news(nid,title)VALUES(news_seq.nextval,'C')");
int result[]=stmt.executeBatch();//执行批处理
conn.commit();//事务提交
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/198165.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot3+Vue3】四【实战篇】-前端(vue基础)

目录 一、项目前置知识 二、使用vscode创建 三、vue介绍 四、局部使用vue 1、快速入门 1.1 需求 1.2 准备工作 1.3 操作 1.3.1 创建html 1.3.2 创建初始html代码 1.3.3 参照官网import vue 1.3.4 创建vue应用实例 1.3.5 准备div 1.3.6 准备用户数据 1.3.7 通过…

【Linux网络】详解使用http和ftp搭建yum仓库,以及yum网络源优化

目录 一、回顾yum的原理 1.1yum简介 yum安装的底层原理&#xff1a; yum的好处&#xff1a; 二、学习yum的配置文件及命令 1、yum的配置文件 2、yum的相关命令详解 3、yum的命令相关案例 三、搭建yum仓库的方式 1、本地yum仓库建立 2、通过http搭建内网的yum仓库 3、…

RabbitMQ消息的可靠性

RabbitMQ消息的可靠性 一 生产者的可靠性 生产者重试 有时候由于网络问题&#xff0c;会出现连接MQ失败的情况&#xff0c;可以配置重连机制 注意&#xff1a;SpringAMQP的重试机制是阻塞式的&#xff0c;重试等待的时候&#xff0c;当前线程会等待。 spring:rabbitmq:conne…

Java读写Jar

Java提供了读写jar的类库Java.util.jar&#xff0c;Java获取解析jar包的工具类如下&#xff1a; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.HashMap; import …

你知道什么是SaaS吗?

你知道什么是SaaS吗&#xff1f; 云服务架构的三个概念 PaaS 英文就是 Platform-as-a-Service&#xff08;平台即服务&#xff09;PaaS&#xff0c;某些时候也叫做中间件。就是把客户采用提供的开发语言和工具&#xff08;例如Java&#xff0c;python, .Net等&#xff09;开…

我叫:选择排序【JAVA】

1.我是个啥子&#xff1f;&#xff1f; 选择式排序&#xff1a;属于内部排序法,从欲排序的数据中,按指定的规则选出某一元素&#xff0c;再依规定交换位置后达到排序的目的。 2.我的思想 基本思想:第一次从arr[0]~arr[n-1]中选取最小值&#xff0c;与arr[0]交换&#xff0c;第…

单张图像3D重建:原理与PyTorch实现

近年来&#xff0c;深度学习&#xff08;DL&#xff09;在解决图像分类、目标检测、语义分割等 2D 图像任务方面表现出了出色的能力。DL 也不例外&#xff0c;在将其应用于 3D 图形问题方面也取得了巨大进展。 在这篇文章中&#xff0c;我们将探讨最近将深度学习扩展到单图像 3…

Transformer中WordPiece/BPE等不同编码方式详解以及优缺点

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

C++基础从0到1入门编程(三)

系统学习C 方便自己日后复习&#xff0c;错误的地方希望积极指正 往期文章&#xff1a; C基础从0到1入门编程&#xff08;一&#xff09; C基础从0到1入门编程&#xff08;二&#xff09; 参考视频&#xff1a; 1.黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难 2.系统…

ubuntu下载conda

系统&#xff1a;Ubuntu18.04 &#xff08;1&#xff09;下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Linux-x86_64.sh 报错错误 403&#xff1a;Forbidden 解决方法 wget -U NoSuchBrowser/1.0 https://mirrors.tuna.tsingh…

Jmeter做接口测试

1.Jmeter的安装以及环境变量的配置 Jmeter是基于java语法开发的接口测试以及性能测试的工具。 jdk&#xff1a;17 (最新的Jeknins&#xff0c;只能支持到17) jmeter&#xff1a;5.6 官网&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 认识JMeter的目录&#xff1…

【Web】Ctfshow SSRF刷题记录1

核心代码解读 <?php $url$_POST[url]; $chcurl_init($url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $resultcurl_exec($ch); curl_close($ch); ?> curl_init()&#xff1a;初始curl会话 curl_setopt()&#xff1a;会…

【力扣面试经典150题】(链表)K 个一组翻转链表

题目描述 力扣原文链接 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只…

【Python数据结构与算法】——(线性结构)精选好题分享,不挂科必看系列

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏:<<Python数据结构与算法专栏>>&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 时间复杂度大小比较 1.time complexity of algorithm A is O(n^3) while algorithm B is O(2^n). Which o…

CentOS 7 安装CMake指定版本3.21.2

背景&#xff1a;今天在CentOS 7 电脑上安装C 日志框架SpdLog-1.12.0&#xff0c;提示如下错误信息&#xff1a; [rootlocalhost build]# cmake .. && make -j CMake Error at CMakeLists.txt:3 (cmake_minimum_required):CMake 3.10...3.21 or higher is required. …

OSI参考模型

目录 一. OSI参考模型的各层功能二. 网络排错三. 网络安全四. 实体、协议、服务和服务访问点SAP五. TCP IP体系结构 一. OSI参考模型的各层功能 \quad \quad \quad \quad 我们首先来看应用层实现的功能 每个字段的各种取值所代表的意思 \quad \quad 比如要保存的文件内容是ab…

DAC实验(DAC 输出三角波实验)(DAC 输出正弦波实验)

DAC 输出三角波实验 本实验我们来学习使用如何让 DAC 输出三角波&#xff0c;DAC 初始化部分还是用 DAC 输出实验 的&#xff0c;所以做本实验的前提是先学习 DAC 输出实验。 使用 DAC 输出三角波&#xff0c;通过 KEY0/KEY1 两个按键&#xff0c;控制 DAC1 的通道 1 输出两种…

论文速览 Arxiv 2023 | DMV3D: 单阶段3D生成方法

注1:本文系“最新论文速览”系列之一,致力于简洁清晰地介绍、解读最新的顶会/顶刊论文 论文速览 Arxiv 2023 | DMV3D: DENOISING MULTI-VIEW DIFFUSION USING 3D LARGE RECONSTRUCTION MODEL 使用3D大重建模型来去噪多视图扩散 论文原文:https://arxiv.org/pdf/2311.09217.pdf…

SQL SERVER 2008安装教程

SQL SERVER 2008安装教程 本篇文章介绍了安装SQL Server 2008企业版的软硬件配置要求&#xff0c;安装过程的详细步骤&#xff0c;以及需要注意的事项。 安装步骤 (1). 在安装文件setup.exe上&#xff0c;单击鼠标右键选择“以管理员的身份运行”&#xff0c;如下图所示&#…

某60区块链安全之不安全的随机数实战一

区块链安全 文章目录 区块链安全不安全的随机数实战一实验目的实验环境实验工具实验原理实验内容攻击过程分析合约源代码漏洞EXP利用 不安全的随机数实战一 实验目的 学会使用python3的web3模块 学会以太坊不安全的随机数漏洞分析及利用 实验环境 Ubuntu18.04操作机 实验工…