jdbc
来源:互联网 发布:好看的古装电影知乎 编辑:程序博客网 时间:2024/05/17 12:05
【JDBC的回顾】
JDBC的概念:
JDBC:JavaData Base Connectivity.
驱动:
JDBC的开发步骤:
步骤一:注册驱动.
步骤二:获得连接.
步骤三:创建执行SQL语句对象.
步骤四:释放资源.
JDBC的API的详解:
DriverManager:
*注册驱动:
*获得连接:
Connection:
*获得执行SQL语句对象.
*Statement createStatement();
*PreparedStatement prepareStatement(String sql);
*CallableStatement prepareCall(String sql);
*进行事务管理:
*setAutoCommit(boolean flag);
*commit();
*rollback();
Statement:
*执行SQL语句:
*int executeUpate(String sql); --执行insertupdate delete语句.
*ResultSet executeQuery(String sql); --执行select语句.
*boolean execute(String sql); --执行select返回true执行其他的语句返回false.
ResultSet:
*遍历结果集:next();
*获得结果集中的数据.getXXX(intc); getXXX(String name);
1.1.2.2步骤分析
步骤一:创建Java项目,引入mysql的驱动包.
步骤二:编写程序
步骤三:注册驱动
步骤四:获得连接
步骤五:执行SQL
步骤六:释放资源
1.1.3代码实现:
抽取工具类:
packagecom.itheima.jdbc.utils;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.sql.Statement;
importjava.util.Properties;
/**
*JDBC的工具类
*@author apple
*
*/
publicclass JDBCUtils {
publicstatic final String DRIVERCLASS;
publicstatic final String URL;
publicstatic final String USERNAME;
publicstatic final String PASSWORD;
static{
//获得属性文件中的数据.
Propertiesproperties = new Properties();
try{
properties.load(newFileInputStream("src/db.properties"));
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
DRIVERCLASS= properties.getProperty("jdbc.driverClass");
URL= properties.getProperty("jdbc.url");
USERNAME= properties.getProperty("jdbc.username");
PASSWORD= properties.getProperty("jdbc.password");
}
//加载驱动:
publicstatic void loadDriver(){
try{
Class.forName(DRIVERCLASS);
}catch (ClassNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
//获得连接:
publicstatic Connection getConnection(){
loadDriver();
Connectionconn = null;
try{
conn= DriverManager.getConnection(URL, USERNAME, PASSWORD);
}catch (SQLException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
returnconn;
}
//释放资源:
publicstatic void release(Statement stmt,Connection conn){
if(stmt!= null){
try{
stmt.close();
}catch (SQLException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
stmt= null;
}
if(conn!= null){
try{
conn.close();
}catch (SQLException e) {
e.printStackTrace();
}
conn= null;
}
}
publicstatic void release(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try{
rs.close();
}catch (SQLException e) {
e.printStackTrace();
}
rs= null;
}
if(stmt!= null){
try{
stmt.close();
}catch (SQLException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
stmt= null;
}
if(conn!= null){
try{
conn.close();
}catch (SQLException e) {
e.printStackTrace();
}
conn= null;
}
}
}
1.2使用连接池改造JDBC的程序:
1.2.1需求:
提升程序运行的效率,采用连接池对JDBC的部分的效率进行提升.
1.2.2分析:
1.2.2.1技术分析:
【连接池的概述】
为什么使用连接池
Connection对象在JDBC使用的时候.使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了.每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池中(内存中).每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.
常见连接池:
DBCP :Apache.
C3P0 :
【连接池的原理】
在javax.sql.DataSource接口--连接池的接口
*功能:初始化多个连接.把多个连接放入到内存中.
*归还:将连接对象放回到内存中.
【自定义连接池--了解】
publicclass MyDataSource implements DataSource{
//创建一个集合List集合.
List<Connection>list = new ArrayList<Connection>();
//初始化连接池的时候,初始化5个连接.
public MyDataSource() {
for(int i = 1; i <= 5; i++) {
Connectionconn = JDBCUtils.getConnection();
list.add(conn);
}
}
@Override
//从连接池中获得连接
publicConnection getConnection() throws SQLException {
if(list.size()==0){
for(int i = 1; i <= 3; i++) {
Connectionconn = JDBCUtils.getConnection();
list.add(conn);
}
}
Connectionconn = list.remove(0);
returnconn;
}
//归还连接:
publicvoid addBack(Connection conn){
list.add(conn);
}
...
}
【自定义连接池中问题】
创建连接池的时候能不能面向接口编程.
额外增加连接池的方法,那么程序员需要记住这些方法.能不能不额外去提供一些方法.
*****解决:就是要去增强Connection的close方法.
1.继承的方法:
*继承的使用条件:能够控制这个类的构造.
2.装饰者模式:(*****)
*装饰者模式的使用条件:
*2.1增强的类和被增强的类实现相同的接口.
*2.2在增强的类中能够获得被增强的类的引用.
*接口中方法过多,只增强其中的一个方法.其他方法都需要原样调用原有方法.
3.动态代理:(*****)
*JDK的动态代理使用条件:
*被代理的对象必须实现接口.
【使用开源连接池优化程序】
DBCP连接池:
核心API:
@Test
/**
* DBCP的一个入门:手动设置参数
*/
publicvoid demo1(){
Connectionconn = null;
PreparedStatementpstmt = null;
//创建连接池:
BasicDataSourcedataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///web07");
dataSource.setUsername("root");
4
try{
//获得连接:
conn= dataSource.getConnection();
//编写SQL语句.
Stringsql = "insert into category values (null,?)";
//预编译SQL:
pstmt= conn.prepareStatement(sql);
//设置参数:
pstmt.setString(1,"鞋靴箱包");
//执行SQL
pstmt.executeUpdate();
}catch(Exceptione){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt,conn);
}
}
@Test
/**
* DBCP的带有配置文件的方式
*/
publicvoid demo2(){
Connectionconn = null;
PreparedStatementpstmt = null;
//创建连接池:
try{
Propertiesproperties = new Properties();
properties.load(newFileInputStream("src/dbcp.properties"));
DataSourcedataSource = BasicDataSourceFactory.createDataSource(properties);
//获得连接:
conn= dataSource.getConnection();
//编写SQL语句.
Stringsql = "insert into category values (null,?)";
//预编译SQL:
pstmt= conn.prepareStatement(sql);
//设置参数:
pstmt.setString(1,"生活用品");
//执行SQL
pstmt.executeUpdate();
}catch(Exceptione){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt,conn);
}
}
DBCP的参数的设置:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=1234
#<!--初始化连接-->
initialSize=10
#最大连接数量
maxActive=50
#<!--最大空闲连接-->
maxIdle=20
#<!--最小空闲连接-->
minIdle=5
#<!--超时等待时间以毫秒为单位6000毫秒/1000等于60秒-->
maxWait=60000
C3P0连接池的使用:
代码实现:
@Test
/**
*手动设置参数的方式:
*/
publicvoid demo1(){
Connectionconn = null;
PreparedStatementstmt = null;
//System.err.println("");
try{
//创建连接池:
ComboPooledDataSourcedataSource = new ComboPooledDataSource();
//设置参数:
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///web07");
dataSource.setUser("root");
4
conn= dataSource.getConnection();
//编写SQL
Stringsql = "insert into category values (null,?)";
//预编译SQL:
stmt= conn.prepareStatement(sql);
//设置参数:
stmt.setString(1,"食品饮料");
stmt.executeUpdate();
}catch(Exceptione){
e.printStackTrace();
}finally{
JDBCUtils.release(stmt,conn);
}
}
@Test
/**
*配置文件的方式:
*/
publicvoid demo2(){
Connectionconn = null;
PreparedStatementstmt = null;
//System.err.println("");
try{
//创建连接池:
ComboPooledDataSourcedataSource = new ComboPooledDataSource("mysql11111");
conn= dataSource.getConnection();
//编写SQL
Stringsql = "insert into category values (null,?)";
//预编译SQL:
stmt= conn.prepareStatement(sql);
//设置参数:
stmt.setString(1,"食品饮料222");
stmt.executeUpdate();
}catch(Exceptione){
e.printStackTrace();
}finally{
JDBCUtils.release(stmt,conn);
}
}
【使用C3P0改写了工具类】
publicclass JDBCUtils2 {
privatestatic final ComboPooledDataSource DATASOURCE =newComboPooledDataSource();
publicConnection getConnection(){
Connectionconn = null;
try{
conn= DATASOURCE.getConnection();
}catch (SQLException e) {
e.printStackTrace();
}
returnconn;
}
...
}
1.3DBUtils完成CRUD的操作
1.3.1需求:
简化DAO的开发.
1.3.2分析:
1.3.2.1技术分析:
DBUtils
【概述】
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核心功能介绍
QueryRunner中提供对sql语句操作的API.
ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
【QueryRunner核心类】
QueryRunner(DataSourceds) ,提供数据源(连接池),DBUtils底层自动维护连接connection
update(Stringsql, Object... params),执行更新数据
query(Stringsql, ResultSetHandler<T> rsh, Object... params),执行查询
【ResultSetHandler结果集处理类】
ArrayHandler
将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
ArrayListHandler
将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。
BeanHandler
将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler
将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
ColumnListHandler
将结果集中指定的列的字段值,封装到一个List集合中
KeyedHandler
将结果集中每一条记录封装到Map<String,Object>,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。
MapHandler
将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值
MapListHandler
将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。
ScalarHandler
它是用于单数据。例如selectcount(*) from表操作。
【DbUtils】
closeQuietly(Connectionconn)关闭连接,如果有异常try后不抛。
commitAndCloseQuietly(Connectionconn)提交并关闭连接
rollbackAndCloseQuietly(Connectionconn)回滚并关闭连接
【事务管理-JDBC】
事务的概述:
什么是事务:事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败.
事务作用:保证在一个事务中多次操作要么全都成功,要么全都失败.
进行事务的管理:
MYSQL中可以有两种方式进行事务的管理:MYSQL数据库默认事务是自动提交的.写一条SQL语句,事务就已经提交了.Oracle数据库事务不自动提交.手动执行commit;
一种:手动开启事务的方式:
*start transaction;
*commit;或者rollback;
二种:设置MYSQL中的自动提交的参数:
showvariables like '%commit%';
*设置自动提交的参数为OFF:
setautocommit = 0; -- 0:OFF 1:ON
java中的事务:
Connection接口的api:★
setAutoCommit(false);//手动开启事务
commit():事务提交
rollback():事务回滚
扩展:了解 Savepoint还原点
void rollback(Savepoint savepoint) :还原到那个还原点
Savepoint setSavepoint() :设置还原点
dao中
一旦出现异常,.
要想避免这事情,必须添加事务,在service添加事务.
为了保证所有的操作在一个事务中,必须保证使用的是同一个连接
在service层我们获取了连接,开启了事务.如何dao层使用此连接呢????
方法1:
向下传递参数.注意连接应该在service释放
方法2:
可以将connection对象绑定当前线程上
jdk中有一个ThreadLocal类,
ThreadLocal 实例通常是类中的 private static 字段,
它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
ThreadLocal的方法:
构造:
new ThreadLocal()
set(Object value):将内容和当前线程绑定
Object get():获取和迪昂前线程绑定的内容
remove():将当前线程和内容解绑
内部维护了map集合
map.put(当前线程,内容);
map.get(当前线程)
map.remove(当前线程)
事务总结:
事务的特性:★★★
ACID
原子性:事务里面的操作单元不可切割,要么全部成功,要么全部失败
一致性:事务执行前后,业务状态和其他业务状态保持一致.
隔离性:一个事务执行的时候最好不要受到其他事务的影响
持久性:一旦事务提交或者回滚.这个状态都要持久化到数据库中
不考虑隔离性会出现的读问题★★
脏读:在一个事务中读取到另一个事务没有提交的数据
不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作)
虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作)
通过设置数据库的隔离级别来避免上面的问题(理解)
read uncommitted 读未提交上面的三个问题都会出现
read committed 读已提交可以避免脏读的发生
repeatable read可重复读可以避免脏读和不可重复读的发生
serializable 串行化 可以避免所有的问题
演示脏读的发生:
将数据库的隔离级别设置成 读未提交
set session transaction isolation level read uncommitted;
查看数据库的隔离级别
select @@tx_isolation;
避免脏读的发生,将隔离级别设置成 读已提交
set session transaction isolation level read committed;
不可避免不可重复读的发生.
避免不可重复读的发生 经隔离级别设置成 可重复读
set session transaction isolation level repeatable read;
演示串行化 可以避免所有的问题
set session transaction isolation level serializable;
锁表的操作.
四种隔离级别的效率
read uncommitted>read committed>repeatable read>serializable
四种隔离级别的安全性
read uncommitted<read committed<repeatable read<serializable
开发中绝对不允许脏读发生.
mysql中默认级别:repeatable read
oracle中默认级别:read committed
java中控制隔离级别:(了解)
Connection的api
void setTransactionIsolation(int level)
level是常量
[项目加强]
1.重复提交:
重复提交:
*添加完商品后转发到列表的Servlet:
*网速比较慢,点击提交的时候点击多次:
令牌机制:
*保证提交只能执行一次,令牌一次有效.
*生成一个令牌:
*放入session中一份.
*放入到页面中,隐藏字段.
*提交到Servlet以后从session中获得一个,从表单中也获得一个.
*让session的令牌失效.
*比较这两个值是否一致.
2.分页的操作分成两类:
查询的时候一次只查
与数据库的交互次数多
数据量特别的大,也不会影响效率
*一次性把所有数据都查询出来,封装到List集合中.List集合中有一个方法.subList(0,3);
*与数据库的交互的次数少.
*数据量特别的大,影响效率.
使用第一种分页显示数据:
*使用SQL语句控制分页:
*MYSQL :使用limit关键字.
*语法:select* from 表limita,b;
*a:从哪开始.默认0
*b:查询几条记录.
*每页显示3条记录第一页:select* from product limit 0,3; -- select * from product limit 3;
*每页显示3条记录第二页:select* from product limit 3,3;
*begin = (currPage - 1) * pageSize;
*SQLServer :使用top关键字.
*Oracle :使用SQL嵌套
【首页】【上一页】【下一页】【尾页】
分页需要的数据:
JSP---Servlet:
当前页数(currPage)
Servlet---JSP:
总页数(totalPage)
总记录(totalCount):selectcount(*) from product;
*计算总页数:
每页显示的记录数(pageSize)
数据的集合List:select* from product limit 0,3;
- jdbc
- JDBC
- jdbc
- JDBC
- jdbc
- JDBC
- JDBC
- JDBC
- JDBC
- JDBC
- JDBC
- JDBC
- JDBC
- JDBC
- jdbc
- JDBC
- JDBC
- jdbc
- 云计算的理解
- 笔记-arm-linux-gnueabi-ld: cannot find common/env_embedded.0的解决方法
- php运用elasticsearch
- SSRS 锁定标题栏
- pat1091-1100
- jdbc
- iOS-线程相关
- Android中更换头像功能的实现
- 初识python
- 深入C++的运算符重载
- 策略模式
- C++学习笔记 4th —— 万能流程控制if语句
- Java动态绑定
- iOS-Block相关