总结 JDBC知识点
* 什么是JDBC
标准,接口,驱动程序
* JDBC编码步骤TCP协议
* 一组接口
DriverManager
Connection
Statement
PreparedStatement
ResultSet
* 语句对象
Statement
PreparedStatement
CallableStatement: 可以调用存储过程
* 几个JDBC知识点
*事务处理
*批量处理
*可滚动处理集
*数据库端分页JDBC实现
-------------------------------------------------------------
01
================================================================
1.JDBC的编码步骤
1) 加载数据库驱动
驱动程序:即是JDBC这组接口的实现类和其他功能类
由数据库厂商提供
导入mysql jar包
2) 创建连接
DriverManager 驱动管理器
DriverManager提供一个静态方法,建立与数据库的连接
getConnection(url,user,pwd)
url:连接数据库地址
jdbc:mysql://ip:3306/数据库名
jdbc:主协议
mysql:子协议
ip:远程其他机器,就是具体的ip
本机127.0.0.1或localhost
3) 发送sql语句并执行
Statement stmt = connection.createStatement();
statement 表示语句对象
int executeUpdate(String sql)
用来发送insert update delete语句
ResultSet executeQuery(String sql)
用来发送select语句,返回结果集
4) 关闭连接
数据库软件同时支持的连接数是有限的,每一个连接都占有着数据库有限的资源,开启连接程序执行结束后
必须及时释放资源,关闭连接
close():关闭语句对象,关闭连接对象
API:
DriverManager:类.驱动管理器
Connection getConnecrion(url,user,pwd);
Connection:连接对象的接口
Statement createStatement();
Statement:语句对象的接口
int executeUpdate(String sql);
发送增删改查sql语句
ResultSet executeQuery(String sql);
发送查询sql语句
2. *加载驱动
*创建连接
*发送sql语句
*处理结果集(如果是查询)
*关闭连接
ResultSet:结果集对象,带有指针的一块内存区域
boolean next();移动结果集指针,默认指针指向第一条记录之前,next()指向第一条记录,
如果有记录,返回true,否则返回false
getXXX(String columnName);获取字段值
02
======================================================================================
PreparedStatement 预处理语句对象
是Statement的子接口
* 避免sql注入
* 提高多次执行同一条sql语句的效率(缓存)
* sql 语句的可读性更好
只要sql中需要拼接java变量,就使用PreparedStatement
sql语句--->预编译---->执行计划
PreparedStatement接口的使用:
* sql语句中有java变量用?替代 ?作为占位符
select * from user where username = ? and password = ?
* 实例化
实例化期间传sql
PreparedStatement pstmt = conn.prepareStatement(sql);
* 装配占位符?的值
pstmt.setString(1,username);
pstmt.setString(2,password);
* 执行sql语句
执行查询
pstmt.excuteQuery();
发送执行增删改查语句
pstmt.excuteUpdate();
------------------------
******解析配置文件
1.获取指向类路径属性文件的输入流
InputStream in = 当前类.class.getClassLoader().getResourceAsStream("db.properties");
prop.load(in);
根据key取值
String url = prop.getProperty("url");
*****
2.还可以用java.util.ResourceBundle解析加载配置文件
ResourceBundle bundle = ResourceBundle.getBundle("db");
String url = bundle.getString("url");
----------------------------------------------------
*******连接池
* 提高效率
不需要对应所有请求,临时创建新的连接
* 可以管理连接数
*成熟的连接池组件
DBCP(DataBase Connection Pool) 核心类(BasicDataSource)
BasicDataSource dataSource = new BasicDataSource();
//加载参数
dataSource = new BasicDataSource();
//读取数据
ResourceBundle bundle = ResourceBundle.getBundle("db");
String url = bundle.getString("jdbc.url");
String username = bundle.getString("jdbc.username");
String password = bundle.getString("jdbc.password");
int initsize = Integer.parseInt(bundle.getString("jdbc.initialSize"));
int maxactive = Integer.parseInt(bundle.getString("jdbc.maxActive"));
int maxwait = Integer.parseInt(bundle.getString("jdbc.maxWait"));
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
//设置初始化连接数
dataSource.setInitialSize(initsize);
//设置最大连接数
dataSource.setMaxActive(maxactive);
//设置最大等待时间
dataSource.setMaxWait(maxwait);
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
jdbc.initialSize=20
jdbc.maxActive=100
jdbc.maxWait=5000
c3p0(不需要写代码读取配置文件,直接配置c3p0-config.xml就好了)
DataSource dataSource = new ComboPooledDataSource("c3p0");
//加载参数
dataSource = new ComboPooledDataSource("c3p0");
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="c3p0">
<property name="user">root</property>
<property name="password">root</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/login</property>
<!--以上的user是数据库的用户,
password是数据库的密码,driverClass是mysql的数据库驱动,jdbcUrl是连接数据库的url -->
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->
<property name="acquireIncrement">5</property>
<!--初始化时获取十个连接,取值应在minPoolSize与maxPoolSize之间 -->
<property name="initialPoolSize">10</property>
<!--连接池中保留的最小连接数 -->
<property name="minPoolSize">10</property>
<!--连接池中保留的最大连接数 -->
<property name="maxPoolSize">50</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">20</property>
<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
------------------------------------------------------
JDBC中的事务处理
事务:
一组操作的逻辑单元
一组添加 一组删除 一组更新
事务具备四个特性(ACID)
----原子性(atomicity):
一个事务是一个不可分割的逻辑单元,一个事务中,所有操作要么成功要么失败(转账业务,一个减少一个增加金额)
----一致性(Consistency):
事务执行的前后,保证数据的完整性
完整性:完备性和正确性
外键字段的值必须是引用其他主键字段的值
(删除主表的数据,从表必须被修改或被删除)
----隔离性(Isolation):
多个事务执行,事务之间互不干扰
数据库软件都有默认的事务隔离级别
隔离级别:
串行化(serialize):多个事务操作同一个表数据,必须排队执行
读已提交(read commited)
读未提交
可重复读
李四 10000 事务没有提交
张三 20000 脏数据
----持久性(Durability):
事务一旦提交,对数据库数据的影响是永久的
***********数据库端事务的操作:
事务开启: 执行第一条增删改sql语句,事务会自动开启
事务结束: commit 提交事务
rollback 回滚事务(撤销事务)
*JDBC默认自动提交事务
------>boolean conn.getAutoCommit();//获取先前提交方式
(批量删除)----->conn.setAutoCommit(false);//将jdbc的自动提交事务取消
------>conn.commit();//显示提交事务
------>(如果有异常)conn.rollback();//撤销事务
------>conn.setAutoCommit(boolean);//在连接放回连接池中之前,还原提交方式
*注意:在MySQL中,就算commit()没写也会自动提交事务,但是在oracle中必须写commit()才会提交事务
*结论:(什么时候用)当出现一组操作(多条insert,update,delete)的需求,必须关注事务
例:
String username1 = "zansan";
String username2 = "lisi";
double money = 10000;
Connection conn = null;
boolean autoCommit = false;
try {
conn = JDBCUtils.getConnection();
//获取默认提交方式
autoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
//账户一减少
String sql = "update account set balance = balance-? where username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setDouble(1, money);
pstmt.setString(2, username1);
pstmt.executeUpdate();
//账户二增加
String sql2 = "update account set balance = balance+? where username = ?";
pstmt = conn.prepareStatement(sql2);
pstmt.setDouble(1, money);
pstmt.setString(2, username2);
pstmt.executeUpdate();
//提交事务
conn.commit();
System.out.println("转账成功");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
conn.setAutoCommit(autoCommit);
JDBCUtils.close(conn);
}
************
03
============================================================================================
1.批量处理(要加事务处理)(减少与数据库交互次数)
*预处理语句对象PreparedStatement
String sql = "delete from user where id = ?"
PreparedStatement pstmt = conn.prepareStatement(sql);
如果删除十条数据,与数据库交互10次
for(int id : ids){
pstmt.setInt(1,id);
//将操作添加到语句列表中
pstmt.addBatch();
//pstmt.executeUpdata();
//一次性缓冲一组数据
在语句对象中维护了一个语句列表
}
//一次性执行一组操作
pstmt.executeBatch();
* addBatch(), 填充语句列表
* executeBatch(),执行语句列表
*******添加一万条数据
public static void main(String[] args){
Connection conn = null;
boolean autocommit = false;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into account(username,balance) values(?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
autocommit = conn.getAutoCommit();
conn.setAutoCommit(false);
for (int i = 0; i <= 10000; i++) {
pstmt.setString(1, "小本"+i);
pstmt.setDouble(2, 1000+i);
pstmt.addBatch();
//每70个提交一次
if(i%70==0){
pstmt.executeBatch();
//清除语句列表
pstmt.clearBatch();
}
}
pstmt.executeBatch();
conn.commit();
System.out.println("执行成功");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
try {
conn.setAutoCommit(autocommit);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JDBCUtils.close(conn);
}
}
}
---------------------------------------------
2.可滚动结果集
默认结果集指针总是从前往后滚动
ResultSet rs = pstmt.executeQuery();
rs.next();
boolean next();从前往后滚
boolean absolute(int row);将结果集指针绝对定位
boolean previous();从后往前滚
---------------------------------------------
3.JDBC分页查询(Mysql)
分页
两种分页方式:
* 内存分页
查询所有数据,存储在内存中
* 数据库端分页(常用)
查询需要的数据(与数据库多次交互)
数据库(mysql)端分页:
例如每页显示3条:
查看第一页:1,2,3
查看第二页:4,5,6
查看第八页:22,23,24
limit关键字:mysql专用分页查询关键字
select id,username from user limit ?,?
int perpage = 5;
int page = 1;
int begin = (page-1)*perpage
*****分页查询
public static void main(String[] args) {
//每页显示的记录数
int perpage = 5;
//当前页
int page = 4;
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select id,username,balance from account limit ?,?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, (page-1)*perpage);
pstmt.setInt(2, perpage);
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString("id")+" "+rs.getString("username")+" "+rs.getString("balance 5"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtils.close(conn);
}
}
**************************************************************************