JDBC学习笔记二
JDBC学习笔记二
4.execute()方法执行SQL语句
execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象。
以下两个方法分别获得结果集或受影响的行数:
getResultSet(): 获取该Statement执行查询语句返回的ResultSet对象
getUpdateCount(): 获取该Statement执行DML语句所影响的记录行数
部分示例代码:
//stmt即为Connection对象创建的Statement
boolean hasResult = stmt.execute(sql);
if(hasResult){
//获取结果集
ResultSet rs = stmt.getResultSet;
}
else{
//获取受影响的行数
int count = stmt.getUpdateCount'
}
5.PreparedStatement
PerparedStatement时Statement的子接口,允许使用?占位符来代替具体值,在通过Connection对象创建PreparedStatement对象时需要传入SQL语句来进行预编译:
PreparedStatement pstmt = conn.prepareStatement("允许带占位符的sql语句");
PerparedStatement在执行SQL语句之前,要通过之前提到过的setXxx(int parameterIndex, Xxx value)方法来对占位符进行赋值。执行语句时的方法跟Statement方法相同,只是不需要传入SQL语句。
PreparedStatement还可以防止SQL注入,Statement如果要使用变量就需要拼接字符串,所以存在SQL注入的风险。
测试代码(使用之前的工具类以及Junit单元测试):
@Test
public void pstmtTest() throws Exception{
String sql = "select * from test where One > ?";
Connection conn = JDBC2.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
//给占位符赋值
pstmt.setInt(1, 1);
//执行SQL语句
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt(1) + " "
+ rs.getString(2) + " " + rs.getString(3));
}
//关闭连接
JDBC2.close(conn, pstmt, rs);
}
结果测试成功,这里就不再贴出
6.CallableStatement
调用存储过程使用CallableStatement,通过Connection的prepareCall方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的SQL语句,示例如下:
CallabeStatement cstmt = conn.prepareCall("call 存储过程名(?, ?, ?)");
可以通过CallableStatement的SetXxx(int indix, Xxx valie)方法为传入参数设置值,传出参数需要调用registerOutParameter方法来注册参数,示例如下:
cstmt.registerOutParameter(int index, Types.数据类型)
简单示例:
SQL中的存储过程
CREATE PROCEDURE simple_test(IN a int ,in b int, out sum int)
BEGIN
SET sum = a + b;
END;
JAVA代码
@Test
public void cstmtTest()throws Exception{
Connection conn = JDBC2.getConnection();
//创建CallableStatement对象
CallableStatement cstmt = conn.prepareCall("call simple_test(?, ?, ?)");
//为传入参数设置值
cstmt.setInt(1, 6);
cstmt.setInt(2, 2);
//注册参数
cstmt.registerOutParameter(3,Types.INTEGER);
cstmt.execute();
System.out.println(cstmt.getInt(3));
}
测试结果为8,这里就不再贴出
7.ResultSet
ResultSet为结果集,其中包含一个指针指向结果集中的某一行,可以利用内置的各种方法来移动指针,常用方法在之前的2.5中已经给出。
在JDK1.4之前的版本中,默认打开的ResultSet是不可滚动的,必须在创建Statement过PreStatement时需要传入额外参数,JDK1.5以后默认打开了ResultSet就是可滚动的,无需传入额外参数。
传入的参数有以下两种类型:
resultSetType:控制ResultSet的类型,该参数可以是三个值:
ResultSet.TYPE_FORWARD_ONLY: 该常量控制记录指针只能向前移动
ResultSet.TYPE_SCROLL_INSENSITIVE:可滚动结果集,但底层数据的改变不会影响ResultSet的值
ResultSet.TYPE_SCROLL_SENSITIVE:可滚动结果集,底层数据的改变会影响ResultSet的值
resultSetConcurrency:控制ResultSet的并发类型,该参数可以是以下两个值:
ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)
ResultSet.CONCUR_UPDATABLE:该常量指示ResultSet是可更新的并发模式
如果要创建可更新的结果集,查询语句查询的数据通常只能来自于同一个数据表,而且查询结果集中的数据列必须包含主键列,否则将会引起更新失败。
示例代码:
@Test
public void rsTest() throws Exception
{
Connection conn = JDBC2.getConnection();
//创建可更新可滚动的ResultSet对象
PreparedStatement pstmt = conn
.prepareStatement("select * from test where One > ?",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
//给占位符赋值
pstmt.setInt(1, 1);
//执行SQL语句
ResultSet rs = pstmt.executeQuery();
//移动到最后
rs.last();
//获取指针当前所在的行数
int rowCount = rs.getRow();
System.out.println("修改前从后往前遍历:");
for(int i = rowCount; i > 0; i--){
//移动到第i行
rs.absolute(i);
System.out.println(rs.getInt(1) + " "
+ rs.getString(2) + " " + rs.getString(3));
//修改指针所在行的第二列的记录
rs.updateString(2, "修改后的"+ i);
//提交修改
rs.updateRow();
}
//正序输出修改后的数据
System.out.println("修改后从前往后遍历");
for(int i = 1; i <= rowCount; i++){
rs.absolute(i);
System.out.println(rs.getInt(1) + " "
+ rs.getString(2) + " " + rs.getString(3));
}
JDBC2.close(conn, pstmt, rs);
}
}
数据库表中的数据也会随之更改。
8.ResultSetMetaData
MetaData的意思是元数据,即描述其他数据的数据,ResultSetMetaData封装了描述ResultSet对象的数据。
根据Result的getMetaDate()方法来获取ResultSetMetaData对象
常用方法如下:
int getColumnCount(): 返回该ResultSet的列数量
String getColumnName(int column): 返回指定索引的列名
int getColumnType(int column): 返回指定索引的列类型
使用过ResultSetMetaData对象后也要释放资源
9.事务
常用方法在中已经在2.2中写出
下面就贴一下简单的示例代码:
@Test
public void transaction() throws Exception{
Connection conn = JDBC2.getConnection();
//关闭自动提交,开启事务
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
//执行sql语句
stmt.executeUpdate("insert into test values(4, '测试commit4', '测试commit4')");
//设置回滚点
//Savepoint savepoint1 = conn.setSavepoint("savepoint1");
stmt.executeUpdate("insert into test values(5, '测试commit5', '测试commit5')");
//回滚事务,不填写回滚点的话则撤销之前所有操作
//conn.rollback(savepoint1);
//提交事务(回滚之后也要提交)
//conn.commit();
JDBC2.close(conn, stmt, null);
}
10.批量更新
多条SQL语句将会被作为一批操作被同时收集,并同时提交。
使用批量更新需要先创建一个Statement对象,然后使用该对象的addBatch方法将多条SQL语句同时收集起来,最后调用Statement对象的executeBatch同时执行这些sql语句,如下所示:
Statement stmt = conn.createStatement();
//收集多条SQL语句
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
...
//同时执行所有SQL语句
stmt.executeBatch();
执行executeBatch()方法将返回一个int[]数组,返回每次执行的所影响的行数,因此如果addBatch()时添加查询语句运行时会出现错误。因此可以在执行批处理前开启事务,当出现错误时回滚到初始状态。
11.连接池
数据库的连接及关闭非常耗费系统资源,为了减少资源浪费,提高程序运行效率,可以采用数据库连接池。
数据库连接池:当程序启动时,系统自动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从池中取出已有的连接使用,当使用完后,不再关闭数据库连接,而是将连接归还给连接池。连接池就类似于之前所学的对象工厂(也是在程序开始运行时,将properties文件中的类实例化)
C3P0和DBCP对比:
| DBCP | C3P0 | |
|---|---|---|
| 对数据连接处理的方式 | 提供最大连接数 | 提供最大空闲时间 |
| 什么时候挂断 | 当连接超过最大连接数 | 自动回收连接 |
| 连接资源是否释放 | 需要自己手动释放资源 | 需要自己手动释放资源 |
| 效率 | 效率比较高 | 效率没有DBCP高 |
| 推荐使用 | spring开发 | hibernate开发 |
11.1.DBCP
需要jar包:common-dbcp,common-pool , common-collections
maven依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
简单模板:
import org.apache.commons.dbcp2.BasicDataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DBCP {
private static BasicDataSource ds;
static{
try{
ds = new BasicDataSource();
//读取配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("src/main/resources/datasource.properties"));
//设置驱动,高版本jar包不需要这一步,如果写的话写成“com.mysql.jdbc.Driver”
//ds.setDriverClassName(prop.getProperty("driver"));
//设置url
ds.setUrl(prop.getProperty("url"));
//用户名
ds.setUsername(prop.getProperty("username"));
//密码
ds.setPassword(prop.getProperty("password"));
//设置连接池初始连接数
ds.setInitialSize(Integer.parseInt(prop.getProperty("initialsize")));
//设置最大活动连接数
ds.setMaxTotal(Integer.parseInt(prop.getProperty("maxactive")));
//设置最小空闲连接
ds.setMinIdle(Integer.parseInt(prop.getProperty("minidle")));
}catch (IOException e){
e.printStackTrace();
}
System.out.println("finish init");
}
public static Connection getConnetion(){
try {
return ds.getConnection();
}catch (SQLException e){
e.printStackTrace();
return null;
}
}
}
上面的属性配置只是常用配置,完整的配置请参考官方文档。
测试代码:
@Test
public void DBCPTest() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = DBCP.getConnetion();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from test");
while(rs.next())
System.out.println(rs.getInt(1) + " "
+ rs.getString(2) + " " + rs.getString(3));
}catch (SQLException e){
e.printStackTrace();
}
finally {
//关闭连接
try {
if(rs != null)
rs.close();
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
11.2.C3P0
需要jar包:c3p0;
maven依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
简单模板:
将DBCP中的BasicDataSource替换为ComboPooledDataSource
驱动,url,用户名和密码设置方式相同,剩余的请参考官方文档
JDBC学习笔记二的更多相关文章
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- 《SQL必知必会》学习笔记二)
<SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...
- NumPy学习笔记 二
NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
随机推荐
- CodeForces - 1253C(思维+贪心)
题意 https://vjudge.net/problem/CodeForces-1253C n个糖果,一天最多吃m个糖果,每个糖果有个值a[i],第d天会变成d*a[i],问吃k(k=1~n)个糖果 ...
- CodeForces - 1255D (模拟+构造+贪心)
题意 https://vjudge.net/problem/CodeForces-1255D rxc的农场里'R'表示有米,现在有K只鸡,给这k只鸡选一些格子,每个鸡可以有多个格子(每个鸡至少吃一个米 ...
- PyCharm2019.3专业版激活
1. 首先到官网下载Professional(专业版),链接地址: https://www.jetbrains.com/pycharm/download/ 具体安装方法这里就不赘述 2. 下载补丁je ...
- PHP注释标记整理
什么是注释标记 我们在平常写代码或看别人写的代码时, 在方法的说明注释中经常会有这样的注释: /** * @param $num * @return array */ 上面的@param @retur ...
- 后台传给前端字符串为null或解析JSON字符错误——SyntaxError: JSON.parse: unterminated string literal at line 1 column 9018638 of the JSON data
第一种情况: 第二种情况: 首先看看你的JSONObject或JSONArray的引用有没有Getter()和Setter()方法,这个必须要加上 问题:两张表双向多对一.一对多时.响应给后台使,出现 ...
- 【转】Redis常见面试题
介绍:Redis 是一个开源的使用 ANSI C 语言编写.遵守 BSD 协议.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的 API的非关系型数据库. 传统数据 ...
- ST表基础模板
ST表是用来求RMQ问题(求区间最大或最小值问题)的实用数据结构,支持\(O(nlog_n)\)建立,\(O(1)\)查询,是比较高效的结构 其原理实质上是DP(我最讨厌的东西) 题面:屠龙宝刀... ...
- 代码问题【TADT//CVPR2019】
paper:Li X, Ma C, Wu B, et al. Target-Aware Deep Tracking[C]. //CVPR2019 调用adam.m时候报错 结构体内容引用自非结构体数组 ...
- Pycharm2019.2.4专业版激活
Pycharm2019.2.4专业版激活 IDE是开发者创建程序时使用的的软件包,它通过简单的用户界面集成多个高度关联的组件,从而最大化提升编程体验和生产效率:本质上,IDE是一种改进代码创建.测试和 ...
- mysql事务隔离级别与设置
mysql数据库,当且仅当引擎是InnoDB,才支持事务: 1.隔离级别 事务的隔离级别分为:未提交读(read uncommitted).已提交读(read committed).可重复读(repe ...