1 JDBC
1.1 JDBC概述
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
今天我们使用的是mysql的驱动mysql-connector-java-5.1.39-bin.jar
1.2 JDBC原理
Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。
JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
1.3 案例分析
我们学习了sql语句的使用,并创建的分类表sort,今天我们将使用JDBC对分类表进行增删改查操作。
#创建数据库
create database day22_JDBC;
#使用数据库
use day22_JDBC;
###创建分类表
create table sort(
sid int PRIMARY KEY ,
sname varchar(100)
);
#初始化数据
insert into sort(sname) values('家电');
insert into sort(sname) values('服饰');
insert into sort(sname) values('化妆品');
1.4 JDBC开发步骤
- 注册驱动,告知JVM使用的是哪一个数据库驱动
- 获得连接,使用JDBC的类,完成数据库的连接
- 获得语句执行平台,通过连接对象获取SQL语句的执行对象
- 执行sql语句,使用执行对象向数据库执行SQL语句,获取数据库的执行结果
- 处理结果
- 释放资源.
1.4.1 导入驱动jar包
1.4.2 API详解:注册驱动
Class.forName("com.mysql.jdbc.Driver");
JDBC规范定义驱动接口:java.sql.Driver,MySql驱动包提供了实现类:com.mysql.jdbc.Driver
DriverManager工具类,提供注册驱动的方法 registerDriver(),方法的参数是java.sql.Driver,所以我们可以通过如下语句进行注册:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
以上代码不推荐使用,存在两方面不足
1. 硬编码,后期不易于程序扩展和维护
2. 驱动被注册两次。
通常开发我们使用Class.forName() 加载一个使用字符串描述的驱动类。
如果使用Class.forName()将类加载到内存,该类的静态代码将自动执行。
通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
……
}
1.4.3 API详解:获得链接
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
获取连接需要方法 DriverManager.getConnection(url,username,password),三个参数分别表示,url 需要连接数据库的位置(网址) user用户名 password 密码
url比较复杂,下面是mysql的url:
jdbc:mysql://localhost:3306/mydb
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
第一部分是jdbc,这是固定的;
第二部分是数据库名称,那么连接mysql数据库,第二部分当然是mysql了;
第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb)组成。
1.4.4 API详解:获得语句执行平台
String sql = "某SQL语句";
获取Statement语句执行平台:Statement stmt = con.createStatement();
常用方法:
int executeUpdate(String sql); --执行insert update delete语句.
ResultSet executeQuery(String sql); --执行select语句.
boolean execute(String sql); --执行select返回true 执行其他的语句返回false.
1.4.5 API详解:处理结果集(执行insert、update、delete无需处理)
ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录,当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的getXXX(int col)方法(与索引从0开始不同个,列从1开始)来获取指定列的数据:
rs.next();//指向第一行
rs.getInt(1);//获取第一行第一列的数据
常用方法:
//获得任意对象
Object getObject(int index)
Object getObject(String name)
//获得字符串
String getString(int index)
Object getObject(String name)
获得整形
int getInt(int index)
Object getObject(String name)
获得双精度浮点型
double getDouble(int index)
Object getObject(String name)
1.4.6 API详解:释放资源
与IO流一样,使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先关闭。
rs.close();
stmt.close();
con.close();
TestDemo.java执行insert、update、delete
package com.qtw.api;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.注册驱动,反射技术,将驱动类加载到内存
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库连接DriverManager类中的静态方法
//public static Connection getConnection(String url,String user, String password)
//返回值是Connection接口的实现类,在mysql驱动程序
String url = "jdbc:mysql://192.168.134.66:3306/Train";
String username = "root";
String password = "root123";
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println(conn);
//3.通过连接对象获取SQL语句的执行对象
//Statement createStatement()
//返回的是Statement接口的实现类对象,,在mysql驱动程序
Statement stat = conn.createStatement();
//4.执行sql语句
//通过执行者对象调用方法,执行sql语句获得结果
//int executeUpdate(String sql) 执行数据库中的语句,insert delete update
//返回值int 操作成功数据多少行
String sql = "INSERT INTO Student(s_id,s_name,s_birth,s_sex) values('10','老王','2000-01-01','男');";
stat.executeUpdate(sql);
//6.释放资源
stat.close();
conn.close();
}
}
TestDemo.java执行select
package com.qtw.api;
import java.sql.*;
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.注册驱动,反射技术,将驱动类加载到内存
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库连接DriverManager类中的静态方法
String url = "jdbc:mysql://192.168.134.66:3306/Train";
String username = "root";
String password = "root123";
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println(conn);
//3.通过连接对象获取SQL语句的执行对象
Statement stat = conn.createStatement();
//4.执行select语句,获取结果集
//ResultSet executeQuery(String sql) 执行select查询
//返回值 ResultSet接口的实现类对象,实现类在mysql驱动中
String sql = "SELECT * FROM Student;";
ResultSet rs = stat.executeQuery(sql);
//5.处理结果集
//ResultSet接口方法 boolean next()返回true有结果集,返回false没有结果集
while(rs.next()){
//获取每列数据,使用ResultSet接口的getXXX方法
System.out.println(rs.getInt("s_id")+" "+rs.getString("s_name")+" "+rs.getString("s_birth")+" "+rs.getString("s_sex"));
}
//6.释放资源
rs.close();
stat.close();
conn.close();
}
}
1.5 SQL注入问题用户登录
在数据库创建用户信息
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100),
password VARCHAR(100)
);
INSERT INTO users (username,password) VALUES ('a','1'),('b','2');
SELECT * FROM users;
-- 登录查询 --
SELECT * FROM users WHERE username = 'a' and password = '1';
-- 改造后 --
SELECT * FROM users WHERE username = 'AAA' and password = 'BBB' or 1=1;
假设有登录案例SQL语句如下:
SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;
此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX’ OR ‘a’=’a时,则真正执行的代码变为:
SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’;
此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。
演示代码如下:
package com.qtw.api;
/*
* Java程序实现用户登录,用户名和密码,数据库检查
* 演示被别人注入攻击
* */
import java.sql.*;
import java.util.Scanner;
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.注册驱动,反射技术,将驱动类加载到内存
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库连接DriverManager类中的静态方法
String url = "jdbc:mysql://192.168.134.66:3306/Train";
String username = "root";
String password = "root123";
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println(conn);
//3.通过连接对象获取SQL语句的执行对象
Statement stat = conn.createStatement();
Scanner sc = new Scanner(System.in);
String user = sc.nextLine();
String pass = sc.nextLine();
//执行sql语句,查询用户名和密码,如果存在登录成功,如果不存在,登录失败
String sql = "SELECT * FROM users WHERE username = '"+user+"' and password = '"+pass+"';";
System.out.println(sql);
ResultSet rs = stat.executeQuery(sql);
while (rs.next()){
System.out.println(rs.getString("username") + "..." + rs.getString("password"));
}
//6.释放资源
rs.close();
stat.close();
conn.close();
}
}
运行结果
为此,我们使用PreparedStatement来解决对应的问题。
1.6 API详解:预处理对象
- 使用PreparedStatement预处理对象时,建议每条sql语句所有的实际参数,都使用逗号分隔。
String sql = "insert into sort(sid,sname) values(?,?)";;
PreparedStatement预处理对象代码:
PreparedStatement psmt = conn.prepareStatement(sql)
常用方法:
- 执行SQL语句:
int executeUpdate(); --执行insert update delete语句.
ResultSet executeQuery(); --执行select语句.
boolean execute(); --执行select返回true 执行其他的语句返回false.
- 设置实际参数
void setXxx(int index, Xxx xx) 将指定参数设置为给定Java的xx值。在将此值发送到数据库时,驱动程序将它转换成一个 SQL Xxx类型值。
演示代码:
package com.qtw.api;
/*
* Java程序实现用户登录,用户名和密码,数据库检查
* 防止被别人注入攻击
* Statement接口实现类,作用执行SQL语句,返回结果集
* 有一个子接口PreparedStatement(SQL预编译存储,多次高效的执行SQL)
* */
import java.sql.*;
import java.util.Scanner;
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.注册驱动,反射技术,将驱动类加载到内存
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库连接DriverManager类中的静态方法
String url = "jdbc:mysql://192.168.134.66:3306/Train";
String username = "root";
String password = "root123";
Connection conn = DriverManager.getConnection(url, username, password);
Scanner sc = new Scanner(System.in);
String user = sc.nextLine();
String pass = sc.nextLine();
//执行sql语句,查询用户名和密码,如果存在登录成功,如果不存在,登录失败
//SQL语句中的参数用?占位
String sql = "SELECT * FROM users WHERE username = ? and password = ?;";
//调用Connection接口的方法prepareStatement,获取PrepareStatement接口的实现类。
PreparedStatement pst = conn.prepareStatement(sql);
//设置参数
pst.setObject(1, user);
pst.setObject(2, pass);
ResultSet rs = pst.executeQuery();
while (rs.next()){
System.out.println(rs.getString("username") + "..." + rs.getString("password"));
}
//6.释放资源
rs.close();
pst.close();
conn.close();
}
}
运行结果
1.7 JDBC工具类
“获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
该工具类提供方法:public static Connection getConn ()。代码如下:
JDBCUtils.java
package com.qtw.api;
import java.sql.*;
/*
* 实现JDBC工具类
* 定义方法,直接返回数据库的连接对象
* */
public class JDBCUtils {
private JDBCUtils(){}
private static Connection conn;
static {
try {
//1.注册驱动,反射技术,将驱动类加载到内存
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库连接DriverManager类中的静态方法
String url = "jdbc:mysql://192.168.134.66:3306/Train";
String username = "root";
String password = "root123";
conn = DriverManager.getConnection(url, username, password);
}catch (Exception ex){
throw new RuntimeException(ex+"数据库连接失败");
}
}
/*
* 定义静态方法,返回数据路的连接对象
* */
public static Connection getConnection(){
return conn;
}
//关闭
public static void close(Connection conn, Statement stat, ResultSet rs){
if(rs != null){
try {
rs.close();
}catch (SQLException ex){}
}
if(stat != null){
try {
stat.close();
}catch (SQLException ex){}
}
if(conn != null){
try {
conn.close();
}catch (SQLException ex){}
}
}
public static void close(Connection conn, Statement stat){
if(stat != null){
try {
stat.close();
}catch (SQLException ex){}
}
if(conn != null){
try {
conn.close();
}catch (SQLException ex){}
}
}
}
TestDemo.java
package com.qtw.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TestDemo {
public static void main(String[] args) throws Exception{
Connection conn = JDBCUtils.getConnection();
System.out.println(conn);
PreparedStatement pst = conn.prepareStatement("SELECT s_name FROM Student;");
ResultSet rs = pst.executeQuery();
while(rs.next()){
System.out.println(rs.getString("s_name"));
}
JDBCUtils.close(conn,pst);
}
}
2 properties配置文件
2.1 使用properties配置文件
开发中获得连接的4个参数(驱动、URL、用户名、密码)通常都存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。
通常情况下,我们习惯使用properties文件,此文件我们将做如下要求:
- 文件位置:任意,建议src下
- 文件名称:任意,扩展名为properties
- 文件内容:一行一组数据,格式是“key=value”.
a) key命名自定义,如果是多个单词,习惯使用点分隔。例如:jdbc.driver
b) value值不支持中文,如果需要使用非英文字符,将进行unicode转换。
2.2 创建配置文件
在项目跟目录下,创建文件,输入“db.properties”文件名。
文件中的内容
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb
user=root
password=root
2.3 测试
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.134.66:3306/Train
user=root
password=root123
JDBCUtilsConfig.java
package com.qtw.api;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/*
* 编写数据库连接的工具类,JDBC工具类
* 获取连接对象采用读取配置文件的方法
* 读取数据库连接,执行一次,static{}
* */
public class JDBCUtilsConfig {
private JDBCUtilsConfig(){}
private static Connection conn;
private static String driverClass;
private static String url;
private static String user;
private static String password;
static {
try {
readConfig();
//连接数据库
Class.forName(driverClass);
conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);
}catch (Exception ex){
throw new RuntimeException(ex+"数据库连接失败");
}
}
/*
* 定义静态方法,返回数据路的连接对象
* */
public static Connection getConnection(){
return conn;
}
/*
* 读取文件
* */
public static void readConfig() throws Exception{
//使用类的加载器,在class文件目录下面寻找文件
InputStream in = PropertiesDemo.class.getClassLoader().getResourceAsStream("db.properties");
Properties pro = new Properties();
pro.load(in);
//获取集合中的键值对
driverClass = pro.getProperty("driver");
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
}
}
TestDemo.java
package com.qtw.api;
import java.sql.Connection;
public class TestDemo {
public static void main(String[] args) throws Exception{
Connection conn = JDBCUtilsConfig.getConnection();
System.out.println(conn);
}
}
3 DBUtils
如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache commons组件一个成员:DBUtils。
DBUtils就是JDBC的简化开发工具包。需要项目导入commons-dbutils-1.6.jar才能够正常使用DBUtils工具。
3.1 概述
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核心功能介绍
1.QueryRunner中提供对sql语句操作的API.
2.ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
3. DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
3.2 QueryRunner核心类
update(Connection conn, String sql, Object... params) ,用来完成表数据的增加、删除、更新操作
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) ,用来完成表数据的查询操作
3.3 QueryRunner实现添加、更新、删除操作
演示代码TestDemo.java
package com.qtw.api;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.Connection;
import java.sql.SQLException;
public class TestDemo {
public static void main(String[] args) throws Exception{
insert();
update();
delete();
}
public static void insert(){
try {
//获取一个用来执行SQL语句的对象 QueryRunner
QueryRunner qr = new QueryRunner();
String sql = "INSERT INTO Student(s_id,s_name,s_birth,s_sex) VALUES(?,?,?,?); ";
Object[] params = {"11","张三","1990-11-22","男"};
Connection conn = JDBCUtilsConfig.getConnection();
int line = qr.update(conn,sql,params);// 用来完成表数据的增加、删除、更新操作
//结果集处理
System.out.println("line = " + line);
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
public static void update(){
try {
//创建一个QueryRunner对象,用来完成SQL语句的执行
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "UPDATE Student SET s_birth = ? WHERE s_id = ?;";
Object[] params = {"1992-11-09","11"};
Connection conn = JDBCUtilsConfig.getConnection();
int line = qr.update(conn, sql, params);
//结果集的处理
System.out.println("line="+line);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void delete(){
try {
//创建一个QueryRunner对象,用来完成SQL语句的执行
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "DELETE FROM Student WHERE s_id = ?";
Object[] params = {"11"};
Connection conn = JDBCUtilsConfig.getConnection();
int line = qr.update(conn, sql, params);
//结果集的处理
System.out.println("line="+line);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
3.4 QueryRunner实现查询操作
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) ,用来完成表数据的查询操作
3.4.1 ResultSetHandler结果集处理类
方法 | 描述 |
---|---|
ArrayHandler | 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值 |
ArrayListHandler | 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。 |
BeanHandler | 将结果集中第一条记录封装到一个指定的javaBean中。 |
BeanListHandler | 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中 |
ColumnListHandler | 将结果集中指定的列的字段值,封装到一个List集合中 |
ScalarHandler | 它是用于单数据。例如select count(*) from 表操作。 |
MapHandler | 将结果集第一行封装到Map集合中,Key 列名, Value 该列数据 |
MapListHandler | 将结果集第一行封装到Map集合中,Key 列名, Value 该列数据,Map集合存储到List集合 |
3.4.2 JavaBean
JavaBean就是一个类,在开发中常用封装数据。具有如下特性
1. 需要实现接口:java.io.Serializable ,通常实现接口这步骤省略了,不会影响程序。
2. 提供私有字段:private 类型 字段名;
3. 提供getter/setter方法:
4. 提供无参构造
Student.java
package com.qtw.api;
public class Student {
private int s_id;
private String s_name;
private String s_birth;
private String s_sex;
public Student() {
super();
}
public int getS_id() {
return s_id;
}
public void setS_id(int s_id) {
this.s_id = s_id;
}
public String getS_name() {
return s_name;
}
public void setS_name(String s_name) {
this.s_name = s_name;
}
public String getS_birth() {
return s_birth;
}
public void setS_birth(String s_birth) {
this.s_birth = s_birth;
}
public String getS_sex() {
return s_sex;
}
public void setS_sex(String s_sex) {
this.s_sex = s_sex;
}
@Override
public String toString() {
return "Student{" +
"s_id=" + s_id +
", s_name='" + s_name + '\'' +
", s_birth='" + s_birth + '\'' +
", s_sex='" + s_sex + '\'' +
'}';
}
}
3.4.3 结果集处理
演示代码TestDemo.java
package com.qtw.api;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class TestDemo {
public static void main(String[] args) throws Exception{
//method1();
//method2();
//method3();
//method4();
//method5();
//method6();
//method7();
method8();
}
//ArrayHandler:将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
public static void method1(){
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student;";
Object[] params = {};
Connection conn = JDBCUtilsConfig.getConnection();
Object[] objArray = qr.query(conn, sql, new ArrayHandler(), params);
//结果集的处理
System.out.println(Arrays.toString(objArray));
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//ArrayListHandler:将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。
public static void method2() {
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student WHERE s_name = ?;";
Object[] params = {"老王"};
Connection conn = JDBCUtilsConfig.getConnection();
List<Object[]> list = qr.query(conn, sql, new ArrayListHandler(), params);
//结果集的处理
for (Object[] objArray : list) {
System.out.println(Arrays.toString(objArray));
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//BeanHandler:将结果集中第一条记录封装到一个指定的javaBean中
public static void method3(){
try{
//获取QueryRunner
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student WHERE s_id=?";
Object[] params = {01};
Connection conn = JDBCUtilsConfig.getConnection();
Student zw = qr.query(conn, sql, new BeanHandler<Student>(Student.class), params);
//结果集处理
System.out.println(zw);
conn.close();
} catch(SQLException e){
throw new RuntimeException(e);
}
}
//BeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
public static void method4(){
try{
//获取QueryRunner
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student WHERE s_name = ?;";
Object[] params = {"老王"};
Connection conn = JDBCUtilsConfig.getConnection();
List<Student> list = qr.query(conn, sql, new BeanListHandler<Student>(Student.class), params);
//结果集处理
for (Student zw : list) {
System.out.println(zw);
}
conn.close();
} catch(SQLException e){
throw new RuntimeException(e);
}
}
//ColumnListHandler:将结果集中指定的列的字段值,封装到一个List集合中
public static void method5(){
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT s_name FROM Student;";
Connection conn = JDBCUtilsConfig.getConnection();
List<String> list = qr.query(conn, sql, new ColumnListHandler<String>());
//结果集的处理
for (String str : list) {
System.out.println(str);
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//ScalarHandler:它是用于单数据。例如select count(*) from 表操作。
public static void method6(){
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT COUNT(s_name) FROM Student;";
Object[] params = {};
Connection conn = JDBCUtilsConfig.getConnection();
Long count = qr.query(conn, sql, new ScalarHandler<Long>(), params);
//结果集的处理
System.out.println("count=" + count);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//MapHandler 将结果集第一行封装到Map集合中,Key 列名, Value 该列数据
public static void method7(){
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student;";
Object[] params = {};
Connection conn = JDBCUtilsConfig.getConnection();
//返回值Map集合
Map<String,Object> map = qr.query(conn, sql, new MapHandler());
//结果集的处理
for(String key:map.keySet()){
System.out.println(key+"..."+map.get(key));
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//MapListHandler 将结果集第一行封装到Map集合中,Key 列名, Value 该列数据,Map集合存储到List集合
public static void method8(){
try {
//获取QueryRunner对象
QueryRunner qr = new QueryRunner();
//执行SQL语句
String sql = "SELECT * FROM Student;";
Object[] params = {};
Connection conn = JDBCUtilsConfig.getConnection();
//返回值Map集合
List<Map<String,Object>> list = qr.query(conn, sql, new MapListHandler());
//结果集的处理
for(Map<String,Object> map:list){
for(String key:map.keySet()){
System.out.println(key+"..."+map.get(key));
}
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4 连接池
实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池
4.1 连接池概述
1. 概念
用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。
2. 规范
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
常见的连接池:DBCP、C3P0。
3. 常见配置
分类 | 属性 | 描述 |
---|---|---|
必须项 | driverClassName | 数据库驱动名称 |
必须项 | url | 数据库的地址 |
必须项 | username | 用户名 |
必须项 | password | 密码 |
基本项(扩展) | maxActive | 最大连接数量 |
基本项(扩展) | minIdle | 最小空闲连接 |
基本项(扩展) | maxIdle | 最大空闲连接 |
基本项(扩展) | initialSize | 初始化连接 |
4.2 DBCP连接池
DBCP也是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。
导入jar包
4.3 编写工具类
JDBCUtils.java
package com.qtw.api;
import org.apache.commons.dbcp.BasicDataSource;
import javax.sql.DataSource;
/*
* 使用DBCP实现数据库的连接池
* 连接池配置,自定义类
* 最基本四项配置
* 对于数据库连接池的其他配置,自定义
* */
public class JDBCUtils {
//创建BasicDataSource类对象
private static BasicDataSource datasource = new BasicDataSource();
//静态代码快,对象BasicDataSource对象中的配置,自定义
static {
datasource.setDriverClassName("com.mysql.jdbc.Driver");
datasource.setUrl("jdbc:mysql://192.168.134.66:3306/Train");
datasource.setUsername("root");
datasource.setPassword("root123");
//对象连接池的连接数量配置。可选的
datasource.setInitialSize(10); //初始化的连接
datasource.setMaxActive(8); //最大连接数量
datasource.setMaxIdle(5); //最大空闲数
datasource.setMinIdle(1); //最小空闲数
}
//定义静态方法,返回BasicDataSource类的对象
public static DataSource getDataSource(){
return datasource;
}
}
4.4 测试
TestDemo.java
package com.qtw.api;
/*
* 测试写好的工具类
* 提供是一个DataSource接口的数据源
* QueryRunner类构造方法,接收DataSource接口的实现类
* 后面,调用update,query,无需传递他们Connection连接对象
*
* */
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import java.sql.SQLException;
import java.util.List;
public class TestDemo {
public static void main(String[] args) throws Exception{
//insert();
select();
}
//定义2个方法,实现数据表的添加,数据表的查询
//QueryRunner类对象
private static QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
//数据表插入数据
public static void insert(){
String sql = "INSERT INTO Student(s_id,s_name,s_birth,s_sex) VALUES (?,?,?,?);";
Object[] params = {"11","小王","2019-11-02","男"};
try{
int row = qr.update(sql,params);
}catch (SQLException ex){
System.out.println(ex);
throw new RuntimeException("数据添加失败");
}
}
public static void select(){
String sql = "SELECT * FROM Student";
try {
List<Object[]> list = qr.query(sql, new ArrayListHandler());
for(Object[] objs:list){
for(Object obj:objs){
System.out.println(obj+"\t");
}
}
}catch (SQLException ex){
System.out.println(ex);
throw new RuntimeException("查询失败");
}
}
}
网友评论