第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();//事务提交
}
相关文章:

第20章 数据库编程
通过本章需要理解JDBC的核心设计思想以及4种数据库访问机制,理解数据库连接处理流程,并且可以使用JDBC进行Oracle数据库的连接,理解工厂设计模式在JDBC中的应用,清楚地理解DriverManager类的作用,掌握Connection、Prep…...

PS学习笔记——初识PS界面
文章目录 PS界面 PS界面 我使用的是PS2021,可能不同版本界面有所不同,但大体来说没有太多差异 可以看到下面这个图就是ps的主界面,大体分为菜单栏、选项栏、工具栏、面板、以及最中央的工作区。 ps中的操作基本都能在菜单栏中找到 可以从菜…...

JDBC,Java连接数据库
下载 JDBC https://mvnrepository.com/ 创建项目,然后创建一个目录并将下载好的 jar 包拷贝进去 选择 Add as Library,让这个目录能被项目识别 连接数据库服务器 在 JDBC 里面,使用 DataSource 类来描述数据库的位置 import com.mysql.cj.…...

java智慧校园信息管理系统源码带微信小程序
一、智慧校园的定义 智慧校园指的是以云计算和物联网为基础的智慧化的校园工作、学习和生活一体化环境。以各种应用服务系统为载体,将教学、科研、管理和校园生活进行充分融合,让校园实现无处不在的网络学习、融合创新的网络科研、透明高效的校务治理、…...
智能电销机器人好做吗?ai机器人有没有用?
电销机器人是基于深度神经学算法和卷积神经网络算法,将网络电话、语音识别、自然语言理解、多轮对话、知识图谱等多个门类集于一身的智能产品。不但能与客户智能交流,更能根据已经设定好的专业话术进行业务描述和问题解答,在电销行业是不可多…...

吴恩达《机器学习》9-1:代价函数
一、引入新标记方法 首先,引入一些新的标记方法,以便更好地讨论神经网络的代价函数。考虑神经网络的训练样本,其中每个样本包含输入 x 和输出信号 y。我们用 L 表示神经网络的层数,表示每层的神经元个数(表示输出层神…...
代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I
代码随想录算法训练营第五十九天 | LeetCode 503. 下一个更大元素 II、42. 接雨水 文章链接:下一个更大元素 II、接雨水 视频链接:下一个更大元素 II、接雨水 1. LeetCode 503. 下一个更大元素 II 1.1 思路 本题是给一个数组求右边第一个比当前元素大的…...

mybatisPlus的简单使用
封装实体类 编写Mapper service层 controller层...

vue+element实现多级表头加树结构
标题两种展示方式 方式一 完整代码: <template><div class"box"><el-tableref"areaPointTable":data"tableData"border:span-method"objectSpanMethod":header-cell-style"tableHeaderMerge"><el-ta…...

internet download manager2024中文绿色版(IDM下载器)
在现代互联网时代,文件下载已经成为我们日常生活中必不可少的一项技能。无论是下载软件、音乐、视频还是其他文件,一个高效的下载方法能够为我们节省时间和精力。本文将为您提供一份简明扼要的下载教程,让您轻松掌握文件下载的技巧。 intern…...

(二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、数据集二、导入数据以及展示部分1.导入数据集以及对数据集进行处理2.展示数据(看看就好) 三(1)、搭建网络进…...
markdown 公式编辑
参考:https://blog.csdn.net/qq_36584673/article/details/117167861...

20231117在ubuntu20.04下使用ZIP命令压缩文件夹
20231117在ubuntu20.04下使用ZIP命令压缩文件夹 2023/11/17 17:01 百度搜索:Ubuntu zip 压缩 https://blog.51cto.com/u_64214/7641253 Ubuntu压缩文件夹zip命令 原创 chenglei1208 2023-09-28 17:21:58博主文章分类:LINUX 小工具 文章标签命令行压缩包U…...
IPKISS Tutorials 1------导入 pdk
IPKISS Tutorials 1------导入 pdk 方法1方法2今天给大家介绍一下如何在 IPKISS 中导入想要使用的 pdk 文件。 方法1 # 导入IPKISS 自带 si_fab PDK from si_fab import all as pdk # 导入amf PDK from amfsip import all as pdk方法2 # 导入IPKISS 自带 si_fab PDK import …...

使用ChatGPT进行数据分析案例——贷款数据分析
目录 数据数据 每一行是一个记录,代表着一笔贷款,每一列是一个特征,一共1万多条数据,最后一列非常重要save_loans是否成功收回...

【数字图像处理】Gamma 变换
在数字图像处理中,Gamma 变换是一种重要的灰度变换方法,可以用于图像增强与 Gamma 校正。本文主要介绍数字图像 Gamma 变换的基本原理,并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。 目录 1. Gamma 变换原理 2. FPGA 布署与实现 2…...

ChatGPT + DALL·E 3
参考链接: https://chat.xutongbao.top/...

【AI视野·今日Robot 机器人论文速览 第六十三期】Thu, 26 Oct 2023
AI视野今日CS.Robotics 机器人学论文速览 Fri, 27 Oct 2023 Totally 27 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers 6-DoF Stability Field via Diffusion Models Authors Takuma Yoneda, Tianchong Jiang, Gregory Shakhnarovich, Matthew R. …...

测试Bard和ChatGPT关于双休的法规和推理
Bard是试验品,chatgpt是3.5版的。 首先带着问题,借助网络搜索,从政府官方网站等权威网站进行确认,已知正确答案的情况下,再来印证两个大语言模型的优劣。 想要了解的问题是,在中国,跟法定工作…...
py查询第三方库的路径
在Python中,你可以使用pkg_resources模块来查询第三方库的路径。这个模块提供了许多有用的函数来处理Python包和资源。 以下是一个简单的示例,展示如何查询第三方库的路径: import pkg_resources# 指定要查询的包名 package_name "第…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...