第二十七天 数据库基础&JDBC使用&工具类Properties&连接池&DBUtils【悟空教程】

第二十七天 数据库基础&JDBC使用&工具类Properties&连接池&DBUtils【悟空教程】

第27天 数据库基础&JDBC使用&工具类Properties&连接池&DBUtils

第1章 数据库

1.1 数据库概述

1.1.1 数据库(数据库管理系统):

数据库就是存储数据的仓库,其本质是一个文件系统,数据库按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。

常见的数据库

MySQL:开源免费的数据库,小型的数据库.已经被Oracle收购了.MySQL6.x版本也开始收费。

Oracle:收费的大型数据库,Oracle公司的产品。Oracle收购SUN公司,收购MYSQL。

DB2:IBM公司的数据库产品,收费的。常应用在银行系统中.

SQLServer:MicroSoft 公司收费的中型的数据库。C#、.net等语言常使用。

SyBase:已经淡出历史舞台。提供了一个非常专业数据建模的工具PowerDesigner。

SQLite:嵌入式的小型数据库,应用在手机端。

Java常用的数据库:MySQL,Oracle。

这里使用MySQL数据库。

1.1.2 数据库

MySQL中可以有多个数据库,数据库是真正存储数据的地方。

1.1.3 数据库与数据库管理系统的关系

1.1.4

数据库中以表为组织单位存储数据。

表类似我们的Java类,每个字段都有对应的数据类型。

那么用我们熟悉的java程序来与关系型数据对比,就会发现以下对应关系。

类----------表

类中属性----------表中字段

对象----------记录

1.1.5 表数据

根据表字段所规定的数据类型,我们可以向其中填入一条条的数据,而表中的每条数据类似类的实例对象。表中的一行一行的信息我们称之为记录。

财务表

账务ID

所属大分类

金额

小分类

账户

创建时间

账务描述

1

收入

15800

彩票收入

招商银行

2015-12-31

年末收入

2

支出

19800

水电支出

交通银行

2016-01-01

电费1000

3

支出

12800

奢侈品支出

现金

2016-01-02

换个爱马

用户表

用户ID

用户名称

用户年龄

1

lisi

23

2

wang

24

3

赵六

48

进而有类似如下的对应关系:

1.1.6 SQL语句

数据库是不认识JAVA语言的,但是我们同样要与数据库交互,这时需要使用到数据库认识的语言SQL语句,它是数据库的代码。

结构化查询语言(Structured Query Language)简称SQL,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。

创建数据库、创建数据表、向数据表中添加一条条数据信息均需要使用SQL语句。

1.2 MySql使用

  • 安装

官网下载安装文档:www.javahelp.com.cn

安装后,MySQL会以windows服务的方式为我们提供数据存储功能。开启和关闭服务的操作:右键点击我的电脑→管理→服务→可以找到MySQL服务开启或关闭

  • 登录

MySQL是一个需要账户名密码登录的数据库,登陆后使用,它提供了一个默认的root账号,使用安装时设置的密码即可登录。

格式:cmd> mysql –u用户名 –p

密码

例如:mysql -uroot –p

密码

1.3 SQLyog 安装与使用

输入用户名、密码,点击连接按钮,进行访问MySQL数据库进行操作

在Query窗口中,输入SQL代码,选中要执行的SQL代码,按F8键运行,或按执行按钮运行。

1.4 SQL语句句法

1.4.1 SQL分类

  • 数据定义语言:简称DDL(Data Definition Language),用来定义数据库对象:数据库,表,列等。关键字:create,alter,drop等
  • 数据操作语言:简称DML(Data Manipulation Language),用来对数据库中表的记录进行修改。关键字:insert,delete,update等
  • 数据控制语言:简称DCL(Data Control Language),用来定义数据库的访问权限和安全级别,及创建用户。
  • 数据查询语言:简称DQL(Data Query Language),用来查询数据库中表的记录。关键字:select等

1.4.2 SQL通用语法

  • SQL语句可以单行或多行书写,以分号结尾
  • 可使用空格和缩进来增强语句的可读性
  • MySQL数据库的SQL语句不区分大小写,建议使用大写,例如:SELECT * FROM user。
  • 同样可以使用/**/的方式完成注释
  • MySQL中的我们使用的数据类型

类型

描述

int

整型

double

浮点型

varchar

字符串型

date

日期类型,格式为yyyy-MM-dd,只有年月日,没有时分秒

详详细的数据类型(不建议详细阅读!)

分类

类型名称

说明

整数类型

tinyInt

很小的整数

smallint

小的整数

mediumint

中等大小的整数

int(integer)

普通大小的整数

小数类型

float

单精度浮点数

double

双精度浮点数

decimal(m,d)

压缩严格的定点数

日期类型

year

YYYY 1901~2155

time

HH:MM:SS -838:59:59~838:59:59

date

YYYY-MM-DD 1000-01-01~9999-12-31

datetime

YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00~ 9999-12-31 23:59:59

timestamp

YYYY-MM-DD HH:MM:SS 1970~01~01 00:00:01 UTC~2038-01-19 03:14:07UTC

文本、二进制类型

CHAR(M)

M为0~255之间的整数

VARCHAR(M)

M为0~65535之间的整数

TINYBLOB

允许长度0~255字节

BLOB

允许长度0~65535字节

MEDIUMBLOB

允许长度0~167772150字节

LONGBLOB

允许长度0~4,294,967,295字节

TINYTEXT

允许长度0~255字节

TEXT

允许长度0~65535字节

MEDIUMTEXT

允许长度0~167772150字节

LONGTEXT

允许长度0~4294967295字节

VARBINARY(M)

允许长度0~M个字节的变长字节字符串

BINARY(M)

允许长度0~M个字节的定长字节字符串

a) 数据库相关语句

create database 数据库名; 创建数据库

show databases; 查看数据库

show create database 数据库名; 查看建库语句

drop database 数据库名; 删除数据库

use 数据库名; 使用指定数据库

b) 表结构相关语句

  • 建表语句:

create table 表名(

字段1 类型,

字段2 类型,

...

)

  • 主键约束:

主键是用于标识当前记录的字段。它的特点是非空,唯一。

在开发中一般情况下主键是不具备任何含义,只是用于标识当前记录。

1.在创建表时创建主键,在字段后面加上 primary key.

create table tablename(

id int primary key,

.......

)

2. 在创建表时创建主键,在表创建的最后来指定主键

create table tablename(

id int,

.......,

primary key(id)

)

3.删除主键:alter table 表名 drop primary key ;

4.主键自动增长:一般主键是自增长的字段,不需要指定。

添加自增长语句 主键字段后加auto_increment(只适用MySQL)

其他约束:其他约束还有如外键、唯一、非空等基础加强中详解

  • 查看表:

desc 表名; 查看某个现有表的结构

show tables; 查看当前数据库下所有的表

show create table 表名; 查看建表语句

  • 修改/删除表:

rename table 旧表名 to 新表名 修改表名

alter table 表名 add 列名 类型; 添加列操作

alter table 表名 modify 列名 类型; 修改列类型

alter table 表名 drop 列名; 删除列

alter table 表名 change 旧列名 新列名 类型; 修改列名称

drop table 表名; 删除表

truncate 表名; 摧毁表(删除表)

c) 表数据相关语句

  • 插入数据

insert into 表名(列名1,列名2, ...) values(列值1, 列值2, ...); 指定列插入

insert into 表名 values(列值1, 列值2, ...); 不指定列插入(所有列)

注意:

插入的数据应与字段的数据类型相同

数据的大小应该在列的长度范围内

在values中列出的数据位置必须与被加入列的排列位置相对应。

除了数值类型外,其它的字段类型的值必须使用 单引号引起。

如果要插入空值,可以不写字段,或者插入 null。

对于自动增长的列在操作时,直接插入null值即可。

  • 更新(修改)数据

update 表名 set 字段=值 ,... where 条件 修改指定条件的数据,将这条数据的指定列修改为指定值

  • 删除数据

delete from 表名 where 条件 删除指定条件的数据

delete from 表名 删除表内所有数据

truncate table 表名 摧毁表再重新创建表,达到删除表内所有数据

  • 查询语句

select 字段1,字段2,...from 表名; 查询指定字段信息

select * from 表名; 查询表中所有字段

注意:使用"*"在练习,学习过程中可以使用,在实际开发中,不建议使用。

select distinct 字段 from 表名; distinct用于去除重复

使用as 别名可以给表中的字段,表设置别名. 当查询语句复杂时,使用别名可以极大的简便操作。

select 字段 as 别名,字段 AS 别名 from 表名;

我们在sql操作中,可以直接对列进行运算。

  • where子句

where语句表条件过滤。满足条件操作,不满足不操作,多用于数据的查询与修改。

格式 :

select 字段 from 表名 where 条件;

select 字段 from 表名 where name=’香蕉’;

select 字段 from 表名 where price<5;

select 字段 from 表名 where name>5’;

  • where条件种类:

1.比较运算符

> >= < <= = !=(<>)

2.逻辑运算符

And(并且) or (或者) not(取反)

3.between ...and...

在指定范围内

注意:between 后面的值必须是小值 and后面的是大值

4.in

可以比较多个值

5.like

模糊查询

通配符使用:

1.% 匹配多个

2._ 匹配一个

select 字段 from 表名 where 字段 like ‘%果’; #任意个字符+果,以果结尾

select 字段 from 表名 where 字段 like ‘果%’; #果+任意个字符,以果开头

select 字段 from 表名 where 字段 like ‘%果%’; #包含果

select 字段 from 表名 where 字段 like ‘_果’; #某果

select 字段 from 表名 where 字段 like ‘_果_’; #某果某

6.null值操作

is null; 判断为空

is not null; 判断不为空

查询例句如下:

查询所有支出记录

SELECT * FROM gjp_ledger WHERE parent = '支出';

查询出金额价格大于1000的信息

SELECT * FROM gjp_ledger WHERE money >1000;

查询出金额在2000-5000之间的账务信息

SELECT * FROM gjp_ledger WHERE money >=2000 AND money <=5000;

SELECT * FROM gjp_ledger WHERE money BETWEEN 2000 AND 5000;

查询出金额是1000或5000或3500的商品信息

SELECT * FROM gjp_ledger WHERE money =1000 OR money =5000 OR money =3500;

SELECT * FROM gjp_ledger WHERE money IN(1000,5000,3500);

查询出账务的银行有工商银行的账务信息。

SELECT * FROM gjp_ledger WHERE account LIKE "%工商%";

查询出账务描述中是两个字的账务信息

SELECT * FROM gjp_ledger WHERE ldesc LIKE "__";

查询出账务accont不为null账务信息

SELECT * FROM gjp_ledger WHERE account IS NOT NULL;

SELECT * FROM gjp_ledger WHERE NOT account IS NULL;

  • order by子句

order by可以将查询出的结果进行排序。放置在select语句的最后。

ASC 升序 (默认)

DESC 降序

格式:

SELECT * FROM 表名 ORDER BY 字段ASC;

SELECT * FROM 表名 ORDER BY 字段DESC;

SELECT * FROM 表名 ORDER BY 字段DESC LIMIT 3;

查询字段中最贵的3个。(逻辑倒叙排列取三个值)

  • 记录操作-聚合函数

之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;另外聚合函数会忽略空值。

今天我们学习如下五个聚合函数:

count:统计指定列不为NULL的记录行数;

格式:select count(字段) from 表名;

sum:计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;

max:计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;

min:计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;

avg:计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

格式:

select avg(字段) from 表名;

select avg(字段) as ‘平均价格’ from 表名;

查询例句如下:

统计账务表中共有多少条记录

SELECT COUNT(*) FROM gjp_ledger;

统计账务表中金额大于3000的有多少条记录

SELECT COUNT(*) FROM gjp_ledger WHERE money>3000;

统计有多少收入的账务信息

SELECT SUM(money) FROM gjp_ledger WHERE parent = '收入';

SELECT SUM(IFNULL(money,0)) FROM gjp_ledger WHERE parent = '收入';

统计出记录中支出的平均值

SELECT AVG(money) FROM gjp_ledger where parent = '支出';

统计出商品表中收入的最大与最小值

SELECT MAX(money),MIN(money) FROM gjp_ledger;

SELECT MAX(money),MIN(IFNULL(money,0)) FROM gjp_ledger;

  • 分组查询

分组查询是指使用group by字句对查询信息进行分组,例如:我们要统计出gjp_ledger表中所有分类账务的总数量,这时就需要使用group by 来对gjp_ledger表中的商品根据parent进行分组操作。

分组后我们在对每一组数据进行统计。

格式:

select 分组的字段 ,avg(计算的字段) from 表名 group by 分组的字段;

分组操作中的having子名是用于在分组后对数据进行过滤的,作用类似于where条件。

having与where的区别:

1.having是在分组后对数据进行过滤.

where是在分组前对数据进行过滤

格式:select 分组的字段 ,avg(计算的字段) from 表名 where 计算的字段>20 group by 分组的字段 having avg(计算的字段)>20;

逻辑:先确定where语句 然后在确定having语句

2.having后面可以使用分组函数(统计函数)

where后面不可以使用分组函数。

查询例句如下:

对账务分类别统计,求出每一种类账务的总金额

SELECT parent,SUM(money) FROM gjp_ledger GROUP BY parent;

对账务分类别统计,求出每一种类账务的总金额,金额要大于20000才显示

SELECT parent,SUM(money) FROM gjp_ledger GROUP BY parent HAVING SUM(money)>2000;

1.4.3 DOS操作数据乱码解决

我们在dos命令行操作中文时,会报错

insert into user(username,password) values(‘张三’,’123’);

ERROR 1366 (HY000): Incorrect string value: '\xD5\xC5\xC8\xFD' for column 'username' at row 1

原因:

因为mysql的客户端编码的问题我们的是utf8,而系统的cmd窗口编码是gbk

解决方案(临时解决方案):

修改mysql客户端编码。

show variables like 'character%'; 查看所有mysql的编码

在图中与客户端有关的编码设置:

client connetion result 和客户端相关

database server system 和服务器端相关

将客户端编码修改为gbk.

set character_set_results=gbk; / set names gbk;

以上操作,只针对当前窗口有效果,如果关闭了服务器便失效。

如果想要永久修改,通过以下方式:

在mysql安装目录下有my.ini文件

default-character-set=gbk 客户端编码设置

character-set-server=utf8 服务器端编码设置

注意:修改完成配置文件,重启服务

1.5 作业:

1:完成数据库表的创建并插入数据、读取数据

2:完成课上所有SQL练习

第2章 使用JDBC完成分类表增删改查的操作

2.1 JDBC

2.1.1 JDBC概述

JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范

JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。

今天我们使用的是mysql的驱动mysql-connector-java-5.1.37-bin.jar

2.1.2 JDBC原理

Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。

JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

2.1.3 JDBC开发步骤

1. 注册驱动

2. 获得连接

3. 获得语句执行平台

4. 执行sql语句

5. 处理结果

6. 释放资源

2.1.4 导入驱动jar包

创建lib目录,用于存放当前项目需要的所有jar包

选择jar包,右键执行build path / Add to Build Path

2.1.5 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!");

}

}

……

}

import java.sql.SQLException;

import com.mysql.jdbc.Driver;

/*

* 注册 驱动 : 加载 Driver 类 就可以注册了. new Driver(),虽然可以加载类完成注册,但是并不好.

* 用反射的方式加载Driver类.

* Class.forName(类名);

*/

public class Demo {

public static void main(String[] args) throws SQLException, ClassNotFoundException {

System.out.println("连接数据库...... ");

Driver driver = new Driver();

//注册驱动

Class.forName("com.mysql.jdbc.Driver");

System.out.println("注册成功");

}

}

2.1.6 API详解:获得连接

代码:Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb”,”root”,”123”);

获取连接需要方法 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)组成。

2.1.7 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.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

/*

* 获取连接

* DriverManager.getConnection(url, user, password)

* url : 数据的地址.

*

* jdbc:mysql://localhost:3306/mydb

* jdbc: 写死的.

* mysql:写死的.(目前)

* 库的地址 :localhost 本机, 3306 数据库端口. mydb(你指定的库名字)

* user:数据库管理员用户名(root)

* password: 就是root 的 密码. (root)

*/

public class Demo2 {

public static void main(String[] args) throws ClassNotFoundException, SQLException {

// 1. 注册驱动

Class.forName("com.mysql.jdbc.Driver");

String url = "jdbc:mysql://localhost:3306/bj_230";

String user = "root";

String password = "root" ;

// 2. 获取连接

Connection connection = DriverManager.getConnection(url, user, password);

System.out.println(connection); //com.mysql.jdbc.JDBC4Connection@be8464

// 3. 获取 sql 语句的执行者 .

Statement stat = connection.createStatement();

// 4. 执行 sql

String sql = "INSERT INTO goods VALUES(3,'草莓',15,'斤','昌平' )"; // 插入一条记录

int executeUpdate = stat.executeUpdate(sql);

System.out.println("插入记录成功");

//5------------------------------------------

System.out.println(executeUpdate);

// 6. 关闭资源

stat.close();

connection.close();

}

}

2.1.8 API详解:处理结果集

ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录,当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的

1.getXXX(int col)方法(与索引从0开始不同个,列从1开始)来获取指定列的数据:

2.getXXX(String columnName)方法,通过列名字获取指定列的数据。

rs.next();//指向第一行

rs.getInt(1);//获取第一行第一列的数据

常用方法:

  • Object getObject(int col) ,获得任意对象
  • String getString(int col),获得字符串
  • int getInt(int col),获得整形
  • double getDouble(int col),获得双精度浮点型

2.1.9 API详解:释放资源

与IO流一样,使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先关闭。

rs.close();

stmt.close();

con.close();

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.Statement;

/*

* 修改一条记录.

*

* id 为3记录, gname 修改为 桃子 , 产地 修改为平谷, 价格修改为 10块.

*/

public class Test {

public static void main(String[] args) throws Exception {

// 1.注册驱动

Class.forName("com.mysql.jdbc.Driver");

// 2. 获取连接

String url = "jdbc:mysql://localhost:3306/bj_230";

String user ="root" ;

String password = "root" ;

Connection con = DriverManager.getConnection(url, user, password);

// 3.获取 sql语句执行者

Statement stat = con.createStatement();

// 4.执行sql executeUpdate()

String sql ="UPDATE goods SET gname='桃子',area='平谷' ,price=10 WHERE id=3";

stat.executeUpdate(sql);

// 5.没有

// 6.释放资源

stat.close();

con.close();

System.out.println("修改成功 ");

}

}

2.1.10 SQL注入问题

案例:

假设有登录案例SQL语句如下:

SELECT * FROM 用户表

WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;

此时,当用户输入正确的账号u密码后,查询到了信息则让用户登录。

但是当用户输入的账号为XXX 密码为:XXX’ OR ‘a’=’a时

则真正执行的代码变为:

SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ‘a’=’a’;

此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。

为此,我们使用PreparedStatement来解决对应的问题。

2.1.11 API详解:预处理对象

使用处理对象时,建议每条sql语句所有的实际参数,都使用逗号分隔。

String sql = "insert into category(cid,cname) values(?,?)";;

PreparedStatement预处理对象代码:PreparedStatement psmt = conn.prepareStatement(sql)

常用方法:

1. 执行SQL语句:

  • int executeUpdate(); --执行insert update delete语句.
  • ResultSet executeQuery(); --执行select语句.
  • boolean execute(); --执行select返回true 执行其他的语句返回false.

2. 设置实际参数

  • setXxxx(int , T) 通过setter方法将?占位符替换成实际参数
  • 例如:setString() 实际参数类型为hi字符串。

2.1.12 案例:查询所有记录信息

public class JDBCTest {

public static void main(String[] args) {

try {

//1,注册驱动

/*

* 加载MySql的Driver类到内存,MySql的Driver类在自己的静态代码块实现注册驱动的操作

* 1.使用类加载器,完成MySql的Driver类的加载

* Class.forName( 要加载的类名 ); //类名为带有包名的完整路径名称

*/

Class.forName("com.mysql.jdbc.Driver");

//2,获取连接

/*

* 参数1: 要连接的数据库地址 jdbc:mysql://localhost:3306/mydb, 最后的mydb为数据库名称,我们可以改变

* 参数2: 连接数据库时 使用的用户名

* 参数3: 连接数据库时 使用的密码

*/

Connection conn = DriverManager.getConnection(

"jdbc:mysql://localhost:3306/day22_JDBC", "root", "root");

//3,获取SQL语句执行者

Statement stat = conn.createStatement();

//4,执行SQL语句

String sql = "SELECT * FROM sort";

ResultSet resultSet = stat.executeQuery(sql);

//5,处理结果集(遍历结果集合)

while( resultSet.next() ){

//获取当前行的分类ID

String sid = resultSet.getString("sid");//方法参数为数据库表中的列名

//获取当前行的分类名称

String sname = resultSet.getString("sname");

//显示数据

System.out.println(sid+"-----"+sname);

}

//6,释放资源

/*

* 释放resultSet

* 释放Statement

* 释放Connection

*/

resultSet.close();

stat.close();

conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

2.2 工具类

“获得连接”将在之后的增删改查所有功能中都存在,可以封装工具类JDBCUtils提供获取连接方法从而达到代码的重复利用。该工具类提供方法:public static Connection getConnection()。

2.2.1 获得连接方法

package cn.com.javahelp;

import java.sql.Connection;

import java.sql.DriverManager;

/*

* JDBC工具类

*/

public class JDBCUtil {

static String driverName = "com.mysql.jdbc.Driver";

static String url = "jdbc:mysql://localhost:3306/mydatabase";

static String user = "root";

static String password = "123";

static {

// 1. 注册驱动

try {

Class.forName(driverName);

} catch (ClassNotFoundException e) {

System.out.println("数据库驱动注册失败!");

}

}

/**

* 提供获取连接的方法

* @return 连接对象

* @throws Exception

*/

public static Connection getConn() throws Exception {

// 2. 获得连接

Connection conn = DriverManager.getConnection(url,user,password);

//返回连接

return conn;

}

}

2.2.2 使用properties配置文件(选做)

开发中获得连接的4个参数(驱动、URL、用户名、密码)通常都存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。

通常情况下,我们习惯使用properties文件,此文件我们将做如下要求:

1. 文件位置:任意,在指定位置,一般在项目根目录下

2. 文件名称:任意,扩展名为properties

3. 文件内容:一行一组数据,格式是“key=value”.

a) key命名自定义,如果是多个单词,习惯使用点分隔。(习惯性可以使用静态常量方式记录固定的key)例如:jdbc.driver

b) value值不支持中文,如果需要使用非英文字符,将进行unicode转换。(如果没有指定编码,并且默认编码与properties不同,或者使用properties文件默认的iso8859-1会出现乱码)

2.2.3 创建配置文件

右键/New/File,输入“db.properties”文件名。

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mydb

jdbc.user=root

jdbc.password=123

2.2.4 加载配置文件:Properties对象

对应properties文件处理,开发中也使用Properties对象进行。我们将采用加载properties文件获得流,然后使用Properties对象进行处理。

static{

try {

//1 使用Properties处理流

// * 使用load()方法加载指定的流

Properties props = new Properties();

props.load(is);

//2 使用getProperty(key),通过key获得需要的值,

driver = props.getProperty("jdbc.driver");

url = props.getProperty("jdbc.url");

user = props.getProperty("jdbc.user");

password = props.getProperty("jdbc.password");

} catch (Exception e) {

throw new RuntimeException(e);

}

}

2.2.5 获得连接

/**

* 获得连接

* @return

*/

public static Connection getConnection(){

try {

//1 注册驱动

Class.forName(driver);

//2 获得连接

Connection conn = DriverManager.getConnection(url,user,password);

return conn;

} catch (Exception e) {

throw new RuntimeException(e);

}

}

2.3 作业:

1:完成JDBC步骤的课上查询语句,集合昨天学习的多样SQL需求

2:参照课上的查询操作executeQuery,自己完成增删改的操作executeUpdate

第3章 使用DBUtils优化增删改查操作

如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache commons组织的一个成员:DBUtils。

DBUtils就是JDBC的简化开发工具包。需要使用技术:连接池(获得连接),SQL语句都没有少。

3.1 JavaBean组件

JavaBean就是一个类,在开发中常用于封装数据。具有如下特性

1. 需要实现接口:java.io.Serializable ,通常偷懒省略了。

2. 提供私有字段:private 类型 字段名

3. 提供getter/setter方法

4. 提供无参构造

public class Category {

private String cid;

private String cname;

public Category() {

super();

}

public String getCid() {

return cid;

}

public void setCid(String cid) {

this.cid = cid;

}

public String getCname() {

return cname;

}

public void setCname(String cname) {

this.cname = cname;

}

…toString….

}

3.2 DBUtils完成CRUD

3.2.1 概述

DBUitls是Apache组织提供的一个对JDBC进行简单封装的开源工具类,使用DBUItils工具类对数据库进行开发, 使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

DBUtils操作的是数据库表数据,不会使用其进行表结构字段的设置,因为数据库的定义通常是预先已经设置好了。

Dbutils三个核心类介绍

  • QueryRunner中提供对sql语句操作的API。
  • ResultSetHandler接口,用于定义select操作后,怎样封装结果集。
  • DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法。

3.2.2 DBUtils的查询操作

DBUtils的使用是相对固定的步骤,是常规Java项目的基本操作。

  • 导入DBUtils的Jar包 (我们提供的版本为commons-dbutils-1.6.jar)
  • 通过DriverManger注册驱动
  • 通过DriverManager获取连接对象Connection
  • 通过DBUtils的QueryRunner的query方法使用对应的Connection完成SQL操作
  • 针对执行查询语句时,通过不同的ResultSetHandler子类可以在查询数据后,直接将得到的数据封装为想要的数据组织方式

常用Handler(处理方式):

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

它是用于单数据。例如select count(*) from 表操作

3.2.3 DBUtils的增删改操作

在查询数据的基本步骤基础上,使用QueryRunner调用update(String sql, Object... params) ,执行增删改操作。前边的sql可以添加?,其后边的可变参数为前边的?赋值。

在增删改操作中,没有对结果集的操作。

第4章 连接池

4.1 连接池概述

4.1.1 连接池规范

Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池。

常见的连接池:DBCP、C3P0。

这里学习DBCP连接池。C3P0连接池在就业班学习。

4.1.2 连接池技术简述

当多个程序(多个用户)的多个需求时,我们需要创建多个Connection对象,而与数据库创建连接是十分消耗资源的,连接池创建了多个连接,当使用连接操作数据时,会分配一个连接,而这个连接也可供其他程序(用户)的数据库操作使用,类似线程池。

javax.sql包下的 DataSource是线程池接口。可以使用getConnection()方法获取一个连接,如果连接对象Connection是通过连接池获取的,当通过Connection对象调用close()方法时,不再是销毁连接对象,而是将连接对象放回到连接池。

不使用连接池

使用连接池

a) dbcp连接池介绍

DBCP 是 Apache 软件基金组织下的一个优秀的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:

  • Commons-dbcp.jar:连接池的实现
  • Commons-pool.jar:连接池实现的依赖库

Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

b) dbcp连接池配置

//导包加入classpath

// 1.创建连接池对象

BasicDataSource ds = new BasicDataSource();

// 2.设置相关属性

ds.setDriverClassName("com.mysql.jdbc.Driver");

ds.setUrl("xxx");

ds.setUsername("xxx");

ds.setPassword("xxx");

c) DBUtils使用连接池

当拥有了连接池后,我们可以直接使用连接池获取连接对象,完成普通的sql操作。(在获取连接后,关闭连接是将连接返还给连接池)

而在DBUtils的学习过程中,我们使用QueryRunner的空参构造完成,每次请求调用query方法时传入连接对象。

而当有了线程池后,可以调用QueryRunner的带参构造创建对象:

QueryRunner(DataSource connectionPool);

这时,在每次访问数据库时,将无需再传入连接对象。因为在每次使用QueryRunner时,都已经通过连接池获取了连接。

如:

BasicDataSource ds = new BasicDataSource();

ds.setUrl("jdbc:mysql://localhost:3306/javahelp_gjp");//设置数据库连接

ds.setDriverClassName("com.mysql.jdbc.Driver");//设置驱动名称

ds.setUsername("root");//设置登录用户名

ds.setPassword("abc");//设置登录密码

ds.setMaxIdle(3);//连接池最大空闲连接个数

ds.setMaxWait(3000);//连接池最大等待时间

ds.setMaxActive(5);//连接池最大连接个数

ds.setInitialSize(3);//连接池初始化连接个数

QueryRunner qr = new QueryRunner(ds);

//再查询时无需传入连接对象,因为QueryRunner对象已经从连接池中获取了连接

返回值类型 query = qr.query(SQL语句,Handler对象);

4.1.3 编写工具类(最简单方式)

/*

* 创建DBCP连接池工具类

*

* 作用: 配置DBCP连接池,提供获取连接池中连接对象的方法

*/

public class DBCPUtils {

//创建连接池

private static BasicDataSource dataSource = new BasicDataSource();

public static final String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";

public static final String URL = "jdbc:mysql://localhost:3306/day22_jdbc";

public static final String USER_NAME = "root";

public static final String PASSWORD = "root";

//通过静态代码块,完成dataSource对象的信息配置

static {

//指定驱动名称

dataSource.setDriverClassName(DRIVER_CLASS_NAME);

//指定数据库URL

dataSource.setUrl(URL);

//指定数据库连接的用户名

dataSource.setUsername(USER_NAME);

//指定数据库连接的密码

dataSource.setPassword(PASSWORD);

}

/*

* 提供获取连接池中连接对象的方法

*/

public static Connection getConnection(){

try {

return dataSource.getConnection();

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

4.1.4 常见配置项

分类

属性

描述

必须项

driverClassName

数据库驱动名称

url

数据库的地址

username

用户名

password

密码

基本项

maxActive

最大连接数量

minIdle

最小空闲连接

maxIdle

最大空闲连接

initialSize

初始化连接

优化配置(扩展)

logAbandoned

连接被泄露时是否打印

removeAbandoned

是否自动回收超时连接

removeAbandonedTimeout

超时时间(以秒数为单位)

maxWait

超时等待时间以毫秒为单位 1000等于60秒

timeBetweenEvictionRunsMillis

在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位

numTestsPerEvictionRun

在每次空闲连接回收器线程(如果有)运行时检查的连接数量

minEvictableIdleTimeMillis

连接在池中保持空闲而不被空闲连接回收器线程

参考文档:http://commons.apache.org/proper/commons-dbcp/configuration.html

4.2 作业:

1:定义MyDBUtils类,提供连接池方法(提示:所有连接池的属性设置项均可以为静态成员变量)

2:使用QueryRunner带预处理的查询或更新方法,将where条件的值使用?的方式传入

3:分别使用连接池与不使用连接池操作QueryRunner,完成查询。

4:将所有Handler对象使用一遍。sql语句参照day27的课上语句。

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2018-06-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PingCAP的专栏

TiDB 源码阅读系列文章(四)Insert 语句概览

本文为 TiDB 源码阅读系列文章的第四篇。上一篇文章简单介绍了整体流程,无论什么语句,大体上是在这个框架下运行,DDL 语句也不例外。

45450
来自专栏散尽浮华

mysql表名忽略大小写问题记录

问题描述: 一开发同事在linux下调一个程序老是报错说找不到表,但是登陆mysql,show tables查看明明是已经创建了这张表的!!如下: mysql>...

45870
来自专栏后台架构

Sphinx源码学习笔记(一):索引创建

  因为项目开发需要在游戏内部实现玩家名称的模糊查找功能,本身直接使用Sphinx配置mysql可以直接搭建一套模糊匹配的即可支持功能的实现。

53170
来自专栏Java帮帮-微信公众号-技术文章全总结

第三十天-加强2-多表查询&JDBC&连接池&DBUtils&综合案例【悟空教程】

第三十天-加强2-多表查询&JDBC&连接池&DBUtils&综合案例【悟空教程】

18340
来自专栏chenssy

【死磕Sharding-jdbc】---路由&执行

继续以 sharding-jdbc-example-jdbc模块中的 com.dangdang.ddframe.rdb.sharding.example.jdb...

12030
来自专栏全华班

重新认识你认识的Hibernate(二)

Hibernate估计大家已经用过很多年了吧,好多同学说用过Hibernate,不需要你来讲,但再仔细想想,你能告诉我Hibernate是什么吗? 今天带大家重...

41040
来自专栏landv

金蝶k3密码批量修改

18760
来自专栏hotqin888的专栏

golang beego orm无限条件查询,多条件查询,不定条件查询,动态多条件查询sql语句,一个字段匹配多值

其实我的需求就是:一个树状目录,每个目录下都存有成果,给定某一个上级目录id,分页查询出这个目录下以及子孙目录下的所有成果,要求分页。

1.2K20
来自专栏Java3y

JDBC【事务、元数据、改造JDBC工具类】

1.事务 一个SESSION所进行的所有更新操作要么一起成功,要么一起失败 举个例子:A向B转账,转账这个流程中如果出现问题,事务可以让数据恢复成原来一样【A账...

36480
来自专栏前端侠2.0

oracle中,通过触发器,记录每个语句影响总行数

       业务系统中,有一步“抽数”流程,就是把一些数据从其它服务器同步到本库的目标表。这个过程有可能 多人同时抽数,互相影响。有测试人员反应,原来抽过的数...

10820

扫码关注云+社区

领取腾讯云代金券