jdbc

来源:互联网 发布:好看的古装电影知乎 编辑:程序博客网 时间:2024/05/17 12:05

JDBC的回顾】

  • JDBC的概念:

JDBCJavaData Base Connectivity.

  • 驱动:


  • JDBC的开发步骤:

步骤一:注册驱动.

步骤二:获得连接.
步骤三:创建执行SQL语句对象.

步骤四:释放资源.

  • JDBCAPI的详解:

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);

}

...

}


【自定义连接池中问题】

  1. 创建连接池的时候能不能面向接口编程.

  2. 额外增加连接池的方法,那么程序员需要记住这些方法.能不能不额外去提供一些方法.

*****解决:就是要去增强Connectionclose方法.

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

概述

DBUtilsjava编程中的数据库操作实用工具,小巧简单实用。

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集合做为另一个Mapvalue,另一个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

数据的集合Listselect* from product limit 0,3;




原创粉丝点击