第20章 数据库编程

news2024/11/17 21:26:44

通过本章需要理解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.coloradmin.cn/o/1226611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简历技术栈redis点

熟悉Redis常见的数据类型以及缓存问题&#xff0c;如缓存穿透、雪崩 、击穿等 Redis五种数据类型 Redis常用命令 查看所有 keys * 字符串类型string 常用命令 举例&#xff1a; 放置一个字符串数据到redis中&#xff0c;先为数据定义一个名称&#xff0c;比如name,age等&am…

⑩⑤【DB】详解MySQL存储过程:变量、游标、存储函数、循环,判断语句、参数传递..

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL存储过程 1. 介绍2. 使用3. 变量①系统变…

OceanBase:Zone管理

OceanBase 集群由若干个 Zone 组成。从物理层面来讲&#xff0c;一个 Zone 通常是一个独立的物理部署单元&#xff0c;可以是一个数据中心&#xff08;IDC&#xff09;或者云上的一个 Zone&#xff08;可用区&#xff09;&#xff0c;也可以是一个单独的机架&#xff08;Rack&a…

大模型的视觉能力

摘要&#xff1a; 计算机视觉引领了人工智能中深度学习的采用&#xff0c;这表明在大型注释数据集上预训练的模型可以转移到许多下游设置。现在&#xff0c;在网络规模的原始数据而不是策划的数据集上进行预训练&#xff0c;基础大模型在计算机视觉中正在崛起。这些模型…

时间序列与 statsmodels:预测所需的基本概念(2)

时间序列与 statsmodels&#xff1a;预测所需的基本概念&#xff08;2&#xff09; 维托米尔约万诺维奇 跟随 出版于 走向发展 4 分钟阅读 2022 年 1 月 31 日 8 一、说明 在使时间序列平稳后&#xff0c;在本博客中我们应用 SARIMAX 预测并进行深入解释。 二、关于平稳性 …

C++多线程编程(2):四种线程管理方法

文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 线程管理get_idsleep_forsleep_untilyield 线程管理 有一个this_thread的名称空间中定义了许多的线程管理方法&#xff1a; get_id&#xff1a;获取当前线程idsleep_for&#xff1a;当前线程休眠一段时间sleep_…

计算机组成原理-双端口RAM和多模块存储器

文章目录 存取周期总览双端口RAM多体并行存储器低地址交叉编址有多少个存储体合适&#xff08;体号&#xff09;多模块存储器&#xff08;多体存储器&#xff09;总结实际场景 存取周期 总览 双端口RAM RAM&#xff1a;用于主存或高速缓存&#xff0c;断电数据丢失 多体并行…

实验五:Java多线程程序设计

一、线程接力 编写一个应用程序&#xff0c;除了主线程外&#xff0c;还有三个线程&#xff1a;first、second和third。first负责模拟一个红色的按钮从坐标&#xff08;10&#xff0c;60&#xff09;运动到&#xff08;100&#xff0c;60&#xff09;&#xff1b;second负责模…

自动 ARIMA 超参数搜索

一、介绍 这种用于自动超参数搜索进行预测的开发方法可能会花费大量时间&#xff0c;但它可以带来回报&#xff0c;因为当您找到预测模型的最佳参数时&#xff0c;它将节省时间并提高预测的精度。此外&#xff0c;手动尝试可能会花费您最多的时间&#xff0c;但这种方法在某些情…

不知道如何制作产品图册的,赶紧收藏住!

产品图册是展示产品外观、功能和特点的重要工具&#xff0c;对于销售和推广产品至关重要。然而&#xff0c;制作一本高质量的产品图册并不是一件容易的事情。如果你没有经验或者不确定如何着手&#xff0c;那么这篇文章将为你提供一些实用的建议和技巧&#xff0c;帮助你轻松制…

Java调用com组件之jacob

一、背景介绍 现有标准的 win32 com组件&#xff0c;有如下的参数&#xff1a; 属性 值 说明Program IDyinhai.yh_hb_sctrCOM ClassIDCOM ClassName COClass_yh_hb_sctr Interface TypeDual InterfaceInterface NameIyh_hb_sctr 具有一个方法&#xff1a; yh_hb_call( string…

三、LED闪烁

通过LED的闪烁实验&#xff0c;详解Keil MDK中创建mm32单片机的工程的步骤。 1、开发环境 (1)Keil MDK: V5.38.0.0 (2)MCU: mm320163D7P。 2、Keil工程的创建 (1)打开Keil MDK。 (2)点击“Project”→“New μVision Project...”。 (3)选择工程保存地址及工程文件名&…

基于Springboot的地方美食分享网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的地方美食分享网站(有报告)。Javaee项目&#xff0c;springboot项目。 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 项目介绍&#xff1a; 采用…

数据挖掘复盘——apriori

read_csv函数返回的数据类型是Dataframe类型 对于Dataframe类型使用条件表达式 dfdf.loc[df.loc[:,0]2]df: 这是一个DataFrame对象的变量名&#xff0c;表示一个二维的表格型数据结构&#xff0c;类似于电子表格或SQL表。 df.loc[:, 0]: 这是使用DataFrame的.loc属性来进行…

devops底层是怎么实现的

DevOps的3大核心基础架构 简而言之&#xff0c;实现DevOps工具链&#xff0c;基本需要3个核心基础架构&#xff1a; SCM配置管理系统 Automation自动化系统 Cloud云&#xff08;或者说可伸缩的、自服务的、虚拟化系统&#xff09; SCM配置管理系统 SCM中所放置的内容又可以再…

系列十、你说你做过JVM调优和参数配置,请问如何盘点JVM系统的默认值?

一、JVM的参数类型 1.1、标配参数 java -versionjava -help 1.2、XX参数 1.2.1、Boolean类型 公式&#xff1a;-XX:或者- 某个属性值 表示开启、-表示关闭 # 是否打印GC收集细节 -XX:PrintGCDetails -XX:-PrintGCDetails# 是否使用串行垃圾收集器 -XX:UseSerialGC -XX:-UseS…

矩阵的QR分解

矩阵的QR分解 GramSchmidt 设存在 B { x 1 , x 2 , … , x n } \mathcal{B}\left\{\mathbf{x}_{1},\mathbf{x}_{2},\ldots,\mathbf{x}_{n}\right\} B{x1​,x2​,…,xn​}在施密特正交化过程中 q 1 x 1 ∣ ∣ x 1 ∣ ∣ q_1\frac{x_1}{||x_1||} q1​∣∣x1​∣∣x1​​ q k …

网页视频下载工具 iTubeGo mac中文版软件特色

iTubeGo YouTube Downloader mac是一款功能强大的YouTube视频下载工具。 iTubeGo YouTube Downloader mac软件特色 多种格式支持&#xff1a;iTubeGo YouTube Downloader可以将YouTube视频下载为多种常见的视频和音频格式&#xff0c;包括MP4、MP3、AVI、FLV、MOV、WMV等&…

JavaspringbootMYSQL基于移动端的团购网站26449-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 1 绪论 1.1 选题背景 1.2选题目的及意义 1.3springboot框架介绍 2 基于移动端的团购网站系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章…

数学建模值TOPSIS法及代码

TOPSIS法 TOPSIS法简称为优劣距离解法&#xff0c;是一种常见法综合评价方法&#xff0c;其能充分利用原始数据的信息&#xff0c;其结果能精确地反映各个评价方案之间的差距。 模型介绍 上篇文章谈到的层次分析法是有局限性的。比如评价的决策层不能太多&#xff0c;太多的…