1.JDBC定义
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,是oracle公司指定的一套规范
2.JDBC的作用
有了JDBC API,通过JDBC可以通过一套规范操作不同的数据库了(多态的体现),它可向相应数据库发送SQL调用同时,将 Java语言和JDBC结合起来使程序员不必为不同的平台编写不同的应用程序
简单地说,JDBC 可做三件事:
连接数据库
发送sql语句
处理结果
3.组成
它由一组用Java语言编写的类和接口组成
4.使用
驱动:jdbc的实现类.由数据库厂商提供.接口是不可以使用的,使用的话得由它的实现类来使用,就称为驱动。
5.jdbc操作步骤:★
一、注冊载入JDBC驱动程序;
注冊载入驱动driver。也就是强制类载入:其注冊载入JDBC驱动有三种方法:
方法一:Class.forName(DriverName); 当中DriverName=Driver包名。Driver类名;
Oracle的DriverName=“oracle.jdbc.driver.OracleDriver“。
SQLServer的DriverName=“com.microsoft.jdbc.sqlserver.SQLServerDriver“。方法二:Class.forName(DriverName).newInstance();
代码完毕两个功能:第一,把驱动程序载入到内存里;第二。把当前载入的驱动程序自己主动去DriverManager那注冊,DriverManager是JDBC规范中唯一的Java类。
方法三:直接创建一个驱动对象:new oracle.jdbc.driver.OracleDriver()。
MySql的DriverName=“com.mysql.jdbc.Driver“;
二、得到连接对象 Connection
要连接数据库,须要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。
使用DriverManager的getConnectin(Stringurl , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的username与password来获得。
比如://连接MySql数据库,username和password都是root
String url ="jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "root" ;
try{
Connection con =DriverManager.getConnection(url ,username , password ) ;
}catch(SQLException se){
System.out.println("数据库连接失败!");
se.printStackTrace();
}1、DriverManager在JDBC规范中是类而不是接口。它是一个服务类,用于管理JDBC驱动程序,提供getConnection()方法建立应用程序与数据库的连接。当JDBC驱动程序载入到内存时,会自己主动向DriverManager注冊。此行代码发出连接请求,DriverManager类就会用注冊的JDBC驱动程序来创建到数据库的连接。
2、DriverManager.getConnection()是个静态方法。
3、DriverManager在java.sql包中。当我们调用sql包里不论什么一个类(包含接口)的不论什么一个方法时都会报一个编译时异常SQLException。这里我们使用一个try块后跟多个catch块解决。
4、方法參数URL:统一资源定位符。我们连接的数据库在哪台主机上(这个通过ip地址确定),这个主机有可能装了好几种数据库软件,比方SqlServer,mysql,oracle,那么我们连接哪个数据库要通过port号来确定。port号又称服务号监听号,sqlserver为1433,mysql为3306,oracle为1521:。下表列出经常使用数据库软件的url写法:
Oracle: jdbc:oracle:thin:@ip:1521:dbName;
MySql:jdbc:mysql://ip:3306:dbName;
SQLServer:jdbc:sqlserver://ip:1443;databaseName=dbName;5、当使用本机ip地址连接时须要关闭防火墙。否则连接不上,使用localhost或127.0.0.1则不用关闭防火墙。
三、创建 Statement对象
1、运行静态SQL语句。通常通过Statement实例实现。
2、运行动态SQL语句。通常通过PreparedStatement实例实现。
3、运行数据库存储过程。通常通过CallableStatement实例实现。
详细的实现方式:
Statement stmt = con.createStatement();PreparedStatement pstmt=con.prepareStatement(sql);
CallableStatement cstmt =con.prepareCall("{CALLdemoSp(? , ?
)}") ;
四、运行sql语句
Statement接口提供了三种运行SQL语句的方法:executeQuery、executeUpdate 和execute
1、ResultSet executeQuery(String sqlString):运行查询数据库的SQL语句。返回一个结果集(ResultSet)对象。
2、int executeUpdate(String sqlString):用于运行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATETABLE和DROP TABLE等
3、execute(sqlString):用于运行返回多个结果集、多个更新计数或二者组合的 语句。详细实现的代码:
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ; int rows = stmt.executeUpdate("INSERTINTO ...") ; boolean flag =stmt.execute(String sql) ;
五、处理结果 两种情况:
1、运行更新返回的是本次操作影响到的记录数。
2、运行查询返回的结果是一个ResultSet对象。
ResultSet包括符合SQL语句中条件的全部行。而且它通过一套get方法提供了对这些行中数据的訪问。
使用结果集(ResultSet)对象的訪问方法获取数据:
while(rs.next()){
String name = rs.getString("name") ;
String pass = rs.getString(1) ; // 此方法比較高效
}
(列是从左到右编号的,而且从列1開始)
六、关闭资源释放资源
操作完毕以后要把全部使用的JDBC对象全都关闭,以释放JDBC资源。关闭顺序和声明顺序相反:
1、关闭记录集
2、关闭声明
3、关闭连接对象
if(rs != null){ // 关闭记录集
try{
rs.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(stmt != null){ // 关闭声明
try{
stmt.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
举例实现:
1.打开mysql
use day02; show tables;
2.表中的数据为:
3.运行代码如下:
4,测试结果:
package com.jianqi.a_jdbc.a_hello; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class HELLO { public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day02", "root", "root"); String sql="select * from category"; PreparedStatement st=conn.prepareStatement(sql); ResultSet rs=st.executeQuery(); //处理结果 while(rs.next()){ System.out.println(rs.getString("cid")+"::"+rs.getString("cname")); } //释放资源. rs.close(); st.close(); conn.close(); } }
六.Jdbc-API详解
首先需要注意的是:所有的包 都是 java.sql 或者 javax.sql
不要导错包
其次注意下面的几张截图
1.————————————————————————————————————
2.
//注册驱动
//Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new Driver());
//获取连接 ctrl+o 整理包
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234");
3.
4.
——————————————————————————————————————————————————
1.DriverManager
(驱动管理者):管理了一组jdbc的操作 类
常用方法:
方法1:注册驱动 (了解)
static void registerDriver(Driver driver) :首先需要注意的是:通过API文档知道Driver是一个接口
以前学习的new driver是这个driver的实现类通过查看 com.mysql.jdbc.Driver的源码 有如下代码
static {
try {
java.sql.DriverManager.registerDriver(new Driver());//这段代码我们已经写过
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
驱动注册了两次.我们只需要将静态代码块执行一次,类被加载到内存中会执行静态代码块,并且只执行一次.
现在只需要将类加载到内存中即可,上面的代码 registerDriver(自己写的)就不需要使用了:
方式1:
★Class.forName("全限定名");//包名+类名 com.mysql.jdbc.Driver
方式2:
类名.class;
方式3:
对象.getClass();
2.获取连接★★★★
static Connection getConnection(String url, String user, String password)
参数1:告诉我们连接什么类型的数据库及连接那个数据库
协议:数据库类型:子协议 参数
mysql: jdbc:mysql://localhost:3306/数据库名称
oracle: jdbc:oracle:thin@localhost:1521@实例
参数2:账户名 root
参数3:密码
2.Connection
Connection:连接 是一个接口
常用方法:
1.获取语句执行者: ★PreparedStatement (常用)
(了解)Statement createStatement() :获取普通的语句执行者 会出现sql注入问题
★PreparedStatement prepareStatement(String sql) :获取预编译语句执行者,会防止sql先编译,就会防止
(了解)CallableStatement prepareCall(String sql):获取调用存储过程的语句执行者了解:
setAutoCommit(false) :手动开启事务
commit():提交事务
rollback():事务回滚
3.Statement:(很少使用,会出现sql注入的问题,是一个父接口)
语句执行者 接口
4,PreparedStatement:预编译语句执行者 接口
常用方法:
1.可以设置参数:
setXxx(int 第几个问号,Object 实际参数);
常见的方法:
1.setInt
2.setString(使用的多)
3.setObjectpublic class Hello { @Test public void f1(){ System.out.println("hello"); } @Test public void f2() throws Exception{ //注册驱动 //Class.forName("com.mysql.jdbc.Driver"); DriverManager.registerDriver(new Driver()); //获取连接 ctrl+o 整理包 Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234"); //编写sql String sql="select * from category"; //创建语句执行者 PreparedStatement st=conn.prepareStatement(sql); //设置参数 //执行sql ResultSet rs=st.executeQuery(); //处理结果 while(rs.next()){ System.out.println(rs.getString("cid")+"::"+rs.getString("cname")); } //释放资源. rs.close(); st.close(); conn.close(); } //插入一条数据 @Test public void f3(){ Connection conn=null; ResultSet rs=null; PreparedStatement st=null; try { //获取连接 conn=JdbcUtils.getConnection(); //编写sql String sql="insert into category values(?,?)"; //获取语句执行者 st=conn.prepareStatement(sql); //设置参数 st.setString(1, "c006"); st.setString(2, "户外"); //执行sql int i=st.executeUpdate(); //处理结果 if(i==1){ System.out.println("success"); }else{ System.out.println("fail"); } } catch (Exception e) { e.printStackTrace(); } finally { //释放资源 JdbcUtils.closeResource(conn, st, rs); } }
执行sql:
ResultSet executeQuery() :执行 r 语句 返回值 多个:结果集
int executeUpdate() :执行cud 语句 返回值:影响的行数eg:影响的行数
5.ResultSet:结果集 接口
作用:执行查询语句之后返回的结果
常用方法:
boolean next():判断是否有下一条记录,若有返回true且将光标移到下一行,若没有呢则返回false
光标一开始处于第一条记录的上面
获取具体内容
getXxx(int|string)
若参数为int :第几列
若参数为string:列名(字段名)
例如:
获取cname的内容可以通过
getString(2)
getString("cname")
常用方法:
getInt
getString 也可以获取int值
getObject 可以获取任意
七.常见的配置文件格式:
1.properties
里面内容的格式 key=valueeg: driverClass=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day07 user=root password=1234
所以以后就不用修改jdbc连接数据库的过程中的参数,直接修改配置文件即可,那么如何读取配置文件呢:
若我们的配置文件为properties,并且放在src目录下.
我们可以通过 ResourceBundle工具快速获取里面的配置信息
使用步骤:
1.获取ResourceBundle 对象:
static ResourceBundle getBundle("文件名称不带后缀名")eg:src下的jdbc.properties只用写jdbc即可
2.通过ResourceBundle 对象获取配置信息
String getString(String key) :通过执行key获取指定的value所以前面的注册和连接的部分就可以变成下面的:
package com.itheima.utils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ResourceBundle; public class JdbcUtils { static final String DRIVERCLASS; static final String URL; static final String USER; static final String PASSWORD; static { // 块编辑 alt+shift +a // 变大写 ctrl+shift+x // 变小写 ctrl+shift+y // 向下复制一行 alt+ctrl+↓ // 向下添加一个空行 shift + enter // 向上添加一个空行 ctrl+shift + enter // 删除一行 选中行 ctrl+d // 注释或者去掉注释 ctrl+/ // 向下移动一行 alt + ↓ //alt+s生成get set方法 //shift +alt+L补全(Date date= new Date()) // 获取ResourceBundle ctrl+2 l ResourceBundle bundle = ResourceBundle.getBundle("jdbc"); // 获取指定的内容 DRIVERCLASS = bundle.getString("driverClass"); URL = bundle.getString("url"); USER = bundle.getString("user"); PASSWORD = bundle.getString("password"); } static { // 注册驱动 ctrl+shift+f格式化代码 try { Class.forName(DRIVERCLASS); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 获取连接 public static Connection getConnection() throws SQLException { // 获取连接 ctrl+o 整理包 return DriverManager.getConnection(URL, USER, PASSWORD); } /** * 释放资源 * * @param conn * 连接 * @param st * 语句执行者 * @param rs * 结果集 */ public static void closeResource(Connection conn, Statement st, ResultSet rs) { closeResultSet(rs); closeStatement(st); closeConn(conn); } /** * 释放连接 * * @param conn * 连接 */ public static void closeConn(Connection conn) { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } /** * 释放语句执行者 * * @param st * 语句执行者 */ public static void closeStatement(Statement st) { if (st != null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } st = null; } } /** * 释放结果集 * * @param rs * 结果集 */ public static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } } }
注意:
因为这是封装成一个工具类所以,每次获取连接时候都会需要加载配置文件注册,连接,很麻烦
所以把他们放入一个静态代码块,程序只需要执行一次
不过要注意作用域的问题,把那四个信息放入全局变量中,然后加上static,就会放入一个静态区中,是一个常量,所以
还可以用final修饰一下。常量的命令用大写。
2.xml
八.连接池(数据源):
https://www.cnblogs.com/xdp-gacl/p/4002804.html(一篇连接池的详解博客)
1.作用:
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
2.原理:
连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等
3.常用连接池:
DBCP
C3P0
4.连接池种类:
Druid:
Proxool:
Jakarta DBCP:
DDConnectionBroker:
BoneCP:
Primrose;
................................
5.优势:
应用程序直接获取数据库连接的缺点:
用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
人数访问多的话,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出
使用数据库连接池优化程序性能:
九.编写数据库连接池
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
- Connection getConnection()
- Connection getConnection(String username, String password)
归还连接的方法就是以前的释放资源的方法
调用connection.close();逻辑性已将改变(装饰者模式)
- 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
- 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
- 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到LinkedList中是此处编程的难点。
自定义的简单的连接池的实现
package com.jianqi.b_datasourc.d_myConn;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import com.itheima.utils.JdbcUtils;
/**
* 升级的连接池
* @author Administrator
*
*/
public class MyDataSource {
static LinkedList<Connection> pool=new LinkedList<>();
static{
//初始化的时候 需要放入3个连接
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//从连接池中获取连接
public static Connection getConnection(){
//获取连接的时候需要判断list是否为空
if(pool.isEmpty()){
//在添加2个连接进去
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("从池中获取一个连接");
Connection conn = pool.removeFirst();
//将conn进行包装 ,(装饰者模式的思想,就是重写)
// ConnectionWarp myConn = new ConnectionWarp(conn);
ConnectionWarp myConn = new ConnectionWarp(conn,pool);
return myConn;
}
//归还连接的方法
public static void addBack(Connection conn){
//将conn放入到list的最后面即可
pool.addLast(conn);
System.out.println("连接已归还");
}
}
//Test.java
import java.sql.Connection;
import java.sql.SQLException;
public class TestDs {
public static void main(String[] args) throws SQLException {
//创建连接池
MyDataSource ds = new MyDataSource();
//获取连接
Connection conn=ds.getConnection();
System.out.println(conn);
//归还连接
conn.close();
}
}
但由于归还的时候调用的还是addBack的方法,与原来close有差异,可读性变差,逻辑性不强
所以这里讲解一下增强方法(修改一个方法的逻辑)
1.继承
2.装饰者模式(静态代理)
3.动态代理
十.装饰者模式:★★★
使用步骤:
1.装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要增强的方法进行加强
4.对不需要加强的方法调用原来方法eg: 父类的接口Car public interface Car { void run(); void stop(); }
被装饰者实现接口Car public class QQ implements Car { @Override public void run() { System.out.println("qq在跑"); } @Override public void stop() { System.out.println("刹得住车"); } }
装饰者实现接口Car,和装饰者相同 public class CarWarp implements Car { private Car car; public CarWarp(Car car){ this.car=car; } @Override public void run() { System.out.println("加上电池"); System.out.println("我终于可以5秒破百了.."); } @Override public void stop() { car.stop(); } }
测试模块 public class TTT { public static void main(String[] args) { QQ qq = new QQ(); /*qq.run(); qq.stop();*/ CarWarp warp = new CarWarp(qq); warp.run(); warp.stop(); } }
十一.常用的连接池:
DBCP:(理解)
apache组织
使用步骤:
1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
2.使用api
a.硬编码
//创建连接池
BasicDataSource ds = new BasicDataSource();
//配置信息
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day07");
ds.setUsername("root");
ds.setPassword("1234");//获取连接,编写sql,设置参数的操作
Connection conn=ds.getConnection(); String sql="insert into category values(?,?);"; PreparedStatement st=conn.prepareStatement(sql); //设置参数 st.setString(1, "c011"); st.setString(2, "饮料"); int i = st.executeUpdate(); System.out.println(i); JdbcUtils.closeResource(conn, st, null);
b.配置文件
实现编写一个properties文件
//存放配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("src/dbcp.properties"));//读入路径properties添加
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///day07 username=root password=1234
//设置
//prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
//创建连接池
DataSource ds = new BasicDataSourceFactory().createDataSource(prop);...........................
C3P0:(★★★更加简单,代码量少)
hibernate和spring使用
有自动回收空闲连接的功能.
使用步骤:
1.导入jar包(c3p0-0.9.1.2.jar)&buid到路径
2.使用api
a.硬编码(不推荐)
new ComboPooledDataSource()ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day07");
ds.setUsername("root");
ds.setPassword("1234");Connection conn=ds.getConnection();
String sql="insert into category values(?,?);";
PreparedStatement st=conn.prepareStatement(sql);
//设置参数
st.setString(1, "c011");
st.setString(2, "饮料");
int i = st.executeUpdate();
System.out.println(i);
JdbcUtils.closeResource(conn, st, null);
b.配置文件(c3p0.properties 或者 c3p0-config.xml)
c3p0.properties
1:c3p0.properties中的内容修改成c3p0.形式的
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///day07 c3p0.user=root c3p0.password=1234
配置文件的路径:src下
编码只需要一句话,不需要读入路径。
new ComboPooledDataSource()//使用默认的配置c3p0-config.xml
1.它的形式为:
<c3p0-config> <!-- 默认配置,如果没有指定则使用这个配置 --> <default-config> <!-- 基本配置 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day05</property> <property name="user">root</property> <property name="password">1234</property> <!--扩展配置--> <property name="checkoutTimeout">30000</property> <property name="idleConnectionTestPeriod">30</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> </default-config> <!-- 命名的配置 --> <named-config name="itcast"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/xxxx</property> <property name="user">root</property> <property name="password">1234</property> <!-- 如果池中数据连接不够时一次增长多少个 --> <property name="acquireIncrement">5</property> <property name="initialPoolSize">20</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">40</property> <property name="maxStatements">20</property> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置
注意:
ComboPooledDataSource()这个东西最底层已将在src下找到c3p0.properties,然后把配置信息复制过来了
DataSourcUtils的使用:
最终使用工具类把上面的方式一封装得到一个DataSourcUtils
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DataSourceUtils { private static ComboPooledDataSource ds=new ComboPooledDataSource(); /** * 获取数据源 * @return 连接池 */ public static DataSource getDataSource(){ return ds; } /** * 获取连接 * @return 连接 * @throws SQLException */ public static Connection getConnection() throws SQLException{ return ds.getConnection(); } /** * 释放资源 * * @param conn * 连接 * @param st * 语句执行者 * @param rs * 结果集 */ public static void closeResource(Connection conn, Statement st, ResultSet rs) { closeResultSet(rs); closeStatement(st); closeConn(conn); } /** * 释放连接 * * @param conn * 连接 */ public static void closeConn(Connection conn) { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } /** * 释放语句执行者 * * @param st * 语句执行者 */ public static void closeStatement(Statement st) { if (st != null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } st = null; } } /** * 释放结果集 * * @param rs * 结果集 */ public static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } } }
十二.dbutils(完成curd)
注意:DataSourceutils是获取数据源的,是连接数据库的
dbutils是完成连接数据库后增删改查的,这个得一起用,不要搞混
dbutils:
是apache组织的一个工具类,jdbc的框架,更方便我们使用
使用步骤:
1.导入jar包(commons-dbutils-1.4.jar)
2.创建一个queryrunner类
queryrunner作用:操作sql语句
构造方法:
new QueryRunner(Datasource ds);
3.编写sql
4.执行sql
query(..):执行r操作
update(...):执行cud操作eg:QueryRunner qr= new QueryRunner(DataSourceUtils.getDatasource());
十三.DbUtils的核心类或接口
QueryRunner:类名
作用:操作sql语句
构造器:
new QueryRunner(Datasource ds);
注意:
底层帮我们创建连接,创建语句执行者 ,释放资源.
常用方法:
query(..):
update(..):
DbUtils:释放资源,控制事务 类
closeQuietly(conn):内部处理了异常
commitAndClose(Connection conn):提交事务并释放连接
....
ResultSetHandler:封装结果集 接口
ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler, ScalarHandler
(了解)ArrayHandler, 将查询结果的第一条记录封装成数组,返回
(了解)ArrayListHandler, 将查询结果的每一条记录封装成数组,将每一个数组放入list中返回
★★BeanHandler, 将查询结果的第一条记录封装成指定的bean对象,返回
★★BeanListHandler, 将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中 返回.
(了解)ColumnListHandler, 将查询结果的指定一列放入list中返回
(了解)MapHandler, 将查询结果的第一条记录封装成map,字段名作为key,值为value 返回
★MapListHandler, 将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
★ScalarHandler,针对于聚合函数 例如:count(*) 返回的是一个Long值
演示:import java.sql.SQLException; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.ArrayHandler; import org.apache.commons.dbutils.handlers.ArrayListHandler; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.MapHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import org.junit.Test; import com.itheima.domain.Category; import com.itheima.utils.DataSourceUtils; public class ResultHandleDemo { @Test public void arrayHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; Object[] query = qr.query(sql, new ArrayHandler()); System.out.println(Arrays.toString(query)); } @Test public void arrayListHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; List<Object[]> list = qr.query(sql, new ArrayListHandler()); for (Object[] obj : list) { System.out.println(Arrays.toString(obj)); } } @Test public void beanHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; Category bean = qr.query(sql, new BeanHandler<>(Category.class)); System.out.println(bean); } @Test public void beanListHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; List<Category> list = qr.query(sql, new BeanListHandler<>(Category.class)); for (Category bean : list) { System.out.println(bean); } } @Test public void mapHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; Map<String, Object> map = qr.query(sql, new MapHandler()); System.out.println(map); } @Test public void mapListHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select * from category"; List<Map<String, Object>> list = qr.query(sql, new MapListHandler()); for (Map<String, Object> map : list) { System.out.println(map); } } @Test public void scalarHandler() throws SQLException{ QueryRunner qr=new QueryRunner(DataSourceUtils.getDataSource()); String sql="select count(*) from category"; Object obj = qr.query(sql, new ScalarHandler()); System.out.println(obj.getClass().getName()); } }