1、什么是数据库
数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。
2、什么是数据库管理系统
数据库管理系统(DataBase Management System,DBMS):指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。用户通过数据库管理系统访问数据库中表内的数据。
3、数据库表
数据库中以表为组织单位存储数据。
表类似我们的Java类,每个字段都有对应的数据类型。
那么用我们熟悉的java程序来与关系型数据对比,就会发现以下对应关系。
类—–对应—–表
类中属性—–对应—–表中字段
一个对象—-对应——一条记录
4、SQL语法
SQL语句可以单行或多行书写,以分号结尾
MySQL数据库的SQL语句不区分大小写,建议使用大写,例如:SELECT * FROM user。
4.1 创建表
-- 创建表结构
CREATE TABLE users(
uid INT PRIMARY KEY AUTO_INCREMENT,
uname VARCHAR(20),
uaddress VARCHAR(200)
);
-- 查看数据库
SHOW DATABASES;
-- 删除表
DROP TABLE users;
-- 查看数据库中的表
SHOW TABLES;
-- 查看表结构
DESC users;
/*
添加列,添加字段
ALTER TABLE users ADD tel INT;
*/
DESC users;
/*
修改列,在原有的列上修改
修改列名,数据类型约束
ALTER TABLE users MODIFY tel VARCHAR(50)
*/
/*
修改列名
ALTER TABLE users CHANGE tel newtel DOUBLE;
*/
/*
删除列
ALTER TABLE users DROP newtel;
*/
4.2 插入数据
CREATE DATABASE mybase;
SHOW DATABASES;
CREATE TABLE product(
-- 主键列,自动增长
id INT PRIMARY KEY AUTO_INCREMENT,
-- 商品名字,可变字符,非空
pname VARCHAR(100) NOT NULL,
-- 商品的价格,double
price DOUBLE
);
INSERT INTO product (id,sname) VALUES (1,'记事本')
/*
添加数据格式,不考虑主键
格式:
insert into 表名 (列名) values (值)
*/
INSERT INTO product (pname,price) VALUES ('洗衣机',12.01);
/*
添加数据格式,所有值全给出
格式:
insert into 表名 values (全列值)
*/
INSERT INTO product VALUES (2,'微波炉',300.25);
/*
添加数据格式,批量写入
格式:
insert into 表名 (列名1,列名2,列名3) values
(值1,值2,值3),(值1,值2,值3),(值1,值2,值3)
*/
INSERT INTO product(pname,price) VALUES('智能机器人',2599.98),
('沙发',599.98);
4.3 修改表中的数据
/*
对数据进行更新操作
数据在原有的基础上修改
格式:
update 表名 set 列1=值1,列2=值2 where 条件
where 条件:数据中的唯一性
*/
-- 修改智能机器人,价格上调到69999
UPDATE product SET price=69999 WHERE id=3
-- 修改沙发,名字改为冰箱,价格改为3222
UPDATE product SET pname='冰箱',price=3222 WHERE id=4
/*
修改条件的写法:
id=6
id<>6 id不等于6
id<=6
&&--->and
||--->or
!---> not
id in (1,2,3,4,5)
id not in (1,2,3,4)
*/
-- 将洗衣机和微波炉的价格都改为666
UPDATE product SET price=666.33 WHERE id=1 OR id=2
4.4 对表中的数据查询
/*
查询指定列数据
格式:
select 列名1,列名2 from 表名
*/
SELECT zname,zmoney FROM zhangwu;
/*
查询所有列的数据
格式:
select * from 表名
*/
SELECT * FROM zhangwu;
/*
查询去掉重复记录
distinct 关键字 跟随列名
*/
SELECT DISTINCT zname FROM zhangwu;
/*
查询重新命名列
as 关键字
*/
SELECT zname AS '名称' FROM zhangwu;
/*
查询数据中,直接进行数学运算
格式:
列对数字进行计算
*/
SELECT zname,zmoney+50 AS 'sum' FROM zhangwu;
-- 查询所有的吃饭支出
SELECT * FROM zhangwu WHERE zname='吃饭支出';
-- 查询金额大于240
SELECT * FROM zhangwu WHERE zmoney>200;
-- 查询金额在2000到5000之间
SELECT * FROM zhangwu WHERE zmoney>=200 AND zmoney<=500;
-- 查询金额在2000到5000之间
SELECT * FROM zhangwu WHERE zmoney BETWEEN 200 AND 500;
-- 查询金额是100,200,500其中一个
SELECT * FROM zhangwu WHERE zmoney=100 OR zmoney=200 OR zmoney=500
SELECT * FROM zhangwu WHERE zmoney IN (100,247,500)
-- like模糊查询必须配合通配符%(可以表示多个字符,_表示一个字符)
-- 查询所有的支出
SELECT * FROM zhangwu WHERE zname LIKE '%支出'
-- 查询账务名字,五个字符的
SELECT * FROM zhangwu WHERE zname LIKE '_____'
-- 查询账务名不为空的
SELECT * FROM zhangwu WHERE NOT (zname IS NULL);
SELECT * FROM zhangwu WHERE zname IS NOT NULL;
4.4.1 查询排序
/*
查询,对结果集进行排序
升序,降序,对指定列排序
order by 列名 [desc][asc]
desc 降序
asc 升序排列,可以不写
*/
-- 查询账务表,价格进行升序
SELECT * FROM zhangwu ORDER BY zmoney ASC;
-- 查询账务表,价格进行降序
SELECT * FROM zhangwu ORDER BY zmoney DESC;
-- 查询账务表,查询所有的支出,对金额降序排序
-- 先过滤条件 where 查询的结果再排序
SELECT * FROM zhangwu WHERE zname LIKE '%支出%' ORDER BY zmoney DESC;
4.4.2 聚合查询
/*
使用聚合函数查询计算,它是对一列数据进行计算
*/
-- count 求和,对表中的数据的个数求和 count(列名)
-- 查询统计账务表中,一共有多少条数据
SELECT COUNT(*) AS 'count' FROM zhangwu
-- sum求和,对一列中数据进行求和计算 sum(列名)
-- 对账务表查询,多所有的金额求和计算
SELECT SUM(zmoney) AS 'sum' FROM zhangwu
-- 求和,统计所有支出的总金额,当其中一个为空的话则记为0
SELECT SUM(zmoney) FROM zhangwu WHERE zname LIKE '%收入'
-- max函数,对某列数据获取最大值
SELECT MAX(zmoney) FROM zhangwu
4.4.3 分组查询
/*
吃饭支出 共计多少
工资收入 共计多少
服装支出 共计多少
股票收入 共计多少
打麻将支出 共计多少
分组查询:group by 分组的列名
必须跟随聚合函数
select 查询的时候,被分组的列,要出现在select选择列的后面
*/
SELECT SUM(zmoney),zname FROM zhangwu GROUP BY zname
-- 对zname内容进行分组查询,但是只要支出并排序
SELECT SUM(zmoney) AS 'getsum',zname FROM zhangwu WHERE zname LIKE '%支出'
GROUP BY zname ORDER BY getsum DESC;
-- 对zname内容进行分组查询求和,但是只要支出,显示金额大于100
-- 结果集分组查询后,再次进行筛选,不能使用where,分组后再次过滤使用关键字having
SELECT SUM(zmoney) AS 'getsum',zname FROM zhangwu WHERE zname LIKE '%支出'
GROUP BY zname HAVING getsum>100
/*
having和where的区别:
having是在分组后对数据进行过滤
where是在分组前对数据进行过滤
having后面可以使用分组函数(统计函数也就是聚合函数)
where后面不可以使用分组函数
*/
4.4.4 分页查询
-- 起始位置(要查询第几页-1)乘以第二个参数;第二个参数表示每页显示数目
SELECT * FROM sort LIMIT 6,2;-- 要查询第四页,每页显示两条记录
4.4.5 多表查询
-- 订单表
CREATE TABLE orders(
oid VARCHAR(32)PRIMARY KEY,
totalprice DOUBLE
);
-- 订单项表
CREATE TABLE orderitem(
oid VARCHAR(50),
pid VARCHAR(50)
);
-- 添加约束,使得orderitem成为orders和orderitem之间的连接表
ALTER TABLE orderitem ADD CONSTRAINT orderitem_fk FOREIGN KEY(oid)REFERENCES orders(oid);
ALTER TABLE orderitem ADD CONSTRAINT orderitem1_fk FOREIGN KEY(pid)REFERENCES c_product(pid);
SELECT * FROM category;
SELECT * FROM c_product;
-- 交叉连接,得到的是两个表的乘积
SELECT * FROM category,c_product;
-- 显示内连接(inner可以省略)
SELECT * FROM category INNER JOIN c_product ON cid=category_id;
-- 隐式内连接(内连接查询的是两个表的交集)
SELECT * FROM category c,c_product p WHERE c.cid=p.category_id;
-- 左外连接(查询的是左表的全部以及交集部分)
SELECT * FROM category LEFT JOIN c_product ON cid=category_id;
-- 右外连接(查询的是右表的全部以及交集部分)
SELECT * FROM category RIGHT JOIN c_product ON cid=category_id;
-- 子查询(一条select语句结果作为另一条select语法一部分,可以使查询条件、查询结果等)
SELECT * FROM c_product WHERE category_id=(SELECT cid FROM category WHERE cname='化妆品');
4.4.6 主外键约束关系
-- 分类表 主表
CREATE TABLE category(
cid VARCHAR(32) PRIMARY KEY,
cname VARCHAR(100)
);
-- 商品表 从表
CREATE TABLE c_product(
pid VARCHAR(32) PRIMARY KEY,
pname VARCHAR(40),
price DOUBLE,
category_id VARCHAR(32)
);
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','服饰');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p001','联想','5000','c001');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p002','海尔','5000','c001');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p003','雷神','5000','c001');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p004','JACK JONES','800','c002');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p005','真维斯','200','c002');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p006','花花公子','440','c002');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p007','劲霸','2000','c002');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p008','香奈儿','800','c003');
INSERT INTO c_product(pid,pname,price,category_id) VALUES('p009','相宜本草','200','c003');
SELECT * FROM c_product;
-- 声明外键约束
ALTER TABLE c_product ADD FOREIGN KEY(category_id) REFERENCES category(cid);
-- 因为从表product有主表category的引用数据,所以在主表中是无法直接
-- 删除与从表有关联的数据
DELETE FROM category WHERE cid='c002';
-- 要想删除,只有解除主从表的约束关系
ALTER TABLE c_product DROP FOREIGN KEY category_id;
-- 或者先删除从表中与主表有关系的数据,再删除主表中的数据
4.4.7 删除数据
/*
删除表中的数据
格式:
delete from 表名 where 条件
drop table 表名 删除整个数据表
*/
-- 删除热水器
DELETE FROM product WHERE id=8;
5、JDBC
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
5.1.1 简单的JDBC操作数据库
example 1 插入数据
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.Driver;
/*
* JDBC操作数据库的步骤:
* 1、注册驱动
* 告知JVM使用的是哪一个数据库的驱动
* 2、获得连接
* 使用JDBC中的类,完成对MySQL数据库的连接
* 3、获得语句执行平台
* 通过连接对象获取对SQL语句的执行者对象
* 4、执行sql语句
* 使用执行者对象,向数据库执行sql语句
* 获取到数据库的执行后的结果
* 5、处理结果
* 6、释放资源(一堆close())
*
*
* */
public class JDBCDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、注册驱动反射技术,将驱动类加入到内存
//使用java.sql.DriverManager类静态方法registerDriver(Driver driver)
//Driver是一个接口,参数传递,Mysql驱动程序中的实现类
//使用DriverManager.registerDriver(new Driver)这种方式通过读源码发现注册2次驱动,所以不建议这种方式
// DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、获得数据库连接DriverManager类中静态方法
//static Connection getConnection(String url,String user,String password)
//返回值是Connection接口的实现类,在mysql驱动程序中
//url:数据库地址 格式:jdbc:mysql://连接主机IP:端口号/数据库名字
String url="jdbc:mysql://localhost:3306/mybase";
String username="root";
String password="123456";
Connection con=DriverManager.getConnection(url, username, password);
//3、获得语句执行平台,通过数据库连接对象,获取到sql语句的执行者对象
//con对象调用方法 statement createStatement() 获取statement对象,将sql语句发送到数据库
//返回值是statement接口的实现类对象,在mysql驱动程序中
Statement stat=con.createStatement();
//4、执行sql语句
//通过执行者对象调用方法执行sql语句,获取结果
//int executeUpdate(String sql)执行数据库中的sql语句,insert delete update
//返回值int 操作成功数据表多少行
int row=stat.executeUpdate
("INSERT INTO sort(sname,sprice,sdesc) VALUES('汽车用品',50000,'疯狂涨价')");
System.out.println(row);
//6、释放资源 一堆close()
stat.close();
con.close();
}
}
example2 查询数据
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBCDemo1 {
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
Connection con=DriverManager.getConnection(url, user, password);
//3、获得数据库执行者对象
Statement stat=con.createStatement();
//4、执行sql语句获取结果集
//ResultSet executeQuery(String sql)执行sql语句中的select查询
//返回值ResultSet接口的实现类对象,实现类在mysql驱动中
String sql="SELECT * FROM sort";
ResultSet rs=stat.executeQuery(sql);
//5、处理结果集,返回为真的时候说明有查询有结果,返回为假的时候则该查询没有结果,也就是不存在符合该查询的数据
while(rs.next()) {
//获取每列数据,使用的是ResultSet接口中的方法getXX方法参数,建议写String列名
System.out.println(rs.getInt("sid")+" "+rs.getString("sname")+
" "+rs.getDouble("sprice")+" "+rs.getString("sdesc"));
}
rs.close();
stat.close();
}
}
5.1.2 sql预编译存储式操作数据库(防注入攻击)
容易注入攻击
package cn.itcast.demo;
//sql注入攻击用户登陆
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCDemo3 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
Connection con=DriverManager.getConnection(url, user, password);
//3、获取sql的执行对象
Statement stat=con.createStatement();
//4、执行sql语句,获取结果集,查询
Scanner sc=new Scanner(System.in);
String us=sc.nextLine();
String pass=sc.nextLine();
String sql="SELECT * FROM users WHERE username='"+us+"' AND PASSWORD='"+pass+"'";
ResultSet rs=stat.executeQuery(sql);
while(rs.next()) {
/*
* 当这么写的时候就注入攻击成功:
* adfafa
* dasfafdas 'or'1=1
*
* */
System.out.println(rs.getString("username")+" "+rs.getString("password"));
}
rs.close();
stat.close();
con.close();
}
}
防注入攻击
package cn.itcast.demo;
/*
* java程序实现用户登陆,用户名和密码,数据库检查
* 防止注入攻击
* statement接口实现类,作用是执行sql语句,返回结果集
* 有一个子接口PrepareStatement(sql预编译存储,多次高效的执行sql)
* PrepareStatement的实现类也在驱动中,如何获取接口的实现类
*
* 是Connection数据连接对象的方法
* PrepareStatement prepareStatement(String sql)
*
* */
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCDemo2 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
Connection con=DriverManager.getConnection(url, user, password);
//4、执行sql语句,获取结果集,查询
Scanner sc=new Scanner(System.in);
String us=sc.nextLine();
String pass=sc.nextLine();
String sql="SELECT * FROM users WHERE username=? AND PASSWORD=?";
//获取sql的执行对象,调用Connection接口的方法PrepareStatement,获取prepareStatement接口的实现类
//方法中参数,sql语句中的参数全部采用问号占位符
PreparedStatement pst=con.prepareStatement(sql);
//调用pst对象set方法,设置问号占位符上的参数
pst.setObject(1, us);
pst.setObject(2, pass);
//调用方法,执行sql,获取结果集
ResultSet rs=pst.executeQuery();//之所以这里面不用放sql语句是因为con.prepareStatement(sql)已经编译好了
while(rs.next()) {
System.out.println(rs.getString("username")+" "+rs.getString("password"));
}
rs.close();
pst.close();
con.close();
}
}
更新数据操作
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class JDBCDemo4 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
/*
* 使用PrepareStatement接口,实现数据表的更新操作
*
* */
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
Connection con=DriverManager.getConnection(url, user, password);
//拼写修改的sql语句,采用?占位
String sql="UPDATE sort SET sname=?,sprice=? WHERE sid=?";
//调用数据库连接对象con的方法prepareStatement获取sql语句的编译对象
PreparedStatement pst=con.prepareStatement(sql);
//调用pst的方法setXXX设置?占位
pst.setObject(1, "汽车美容");
pst.setObject(2, 4999988);
pst.setObject(3, 7);
//调用pst方法执行sql语句
pst.executeUpdate();
pst.close();
con.close();
}
}
数据查询
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JDBCDemo5 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
/*
* 使用PrepareStatement接口,实现数据表的查询操作
*
* */
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
Connection con=DriverManager.getConnection(url, user, password);
//拼写修改的sql语句,采用?占位
String sql="SELECT * FROM sort";
//调用数据库连接对象con的方法prepareStatement获取sql语句的编译对象
PreparedStatement pst=con.prepareStatement(sql);
//调用pst方法执行sql语句
ResultSet rs=pst.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("sid")+" "+rs.getString("sname")+
" "+rs.getString("sprice")+" "+rs.getString("sdesc"));
}
rs.close();
pst.close();
con.close();
}
}
封装查询到的数据
Sort.java
package cn.itcast.domain;
public class Sort {
private int sid;
private String sname;
private double sprice;
private String sdesc;
public Sort(int sid, String sname, double sprice, String sdesc) {
this.sid = sid;
this.sname = sname;
this.sprice = sprice;
this.sdesc = sdesc;
}
public Sort() {
super();
// TODO Auto-generated constructor stub
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public double getSprice() {
return sprice;
}
public void setSprice(double sprice) {
this.sprice = sprice;
}
public String getSdesc() {
return sdesc;
}
public void setSdesc(String sdesc) {
this.sdesc = sdesc;
}
@Override
public String toString() {
return "Sort [sid=" + sid + ", sname=" + sname + ", sprice=" + sprice + ", sdesc=" + sdesc + "]";
}
}
package cn.itcast.demo2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import cn.itcast.domain.Sort;
import cn.itcast.jdbcutil.JDBCUtils;
/*
* JDBC读取数据表sort,每行数据封装到sort类的对象中
* 很多个Sort类对象,存储到List集合中
*
* */
public class JDBCDemo1 {
public static void main(String[] args) throws Exception {
//使用JDBC工具类,直接获取数据库连接对象
Connection con=JDBCUtils.getConnection();
//连接获取数据库sql语句执行者对象
PreparedStatement pst=con.prepareStatement("SELECT * FROM sort");
//调用查询方法,获取结果集
ResultSet rs=pst.executeQuery();
//创建集合对象
List<Sort>list=new ArrayList<Sort>();
while(rs.next()) {
//获取到每个列数据,封装到Sort对象中
Sort s=new Sort(rs.getInt("sid"),rs.getString("sname"),rs.getDouble("sprice"),rs.getString("sdesc"));
//封装的sort对象,存储到集合中
list.add(s);
}
JDBCUtils.close(con, rs, pst);
//遍历List集合
for(Sort s:list) {
System.out.println(s);
}
}
}
加载配置文件的方式连接数据库
database.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybase
username=root
password=123456
package cn.itcast.demo2;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/*
* 加载properties配置文件
* IO读取文件,键值对存储到集合
* 从集合中以键值对方式获取数据库的连接信息,完成数据库的连接
*
* */
public class PropertiesDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
// TODO Auto-generated method stub
//使用类的加载器
InputStream in=PropertiesDemo.class.getClassLoader().getResourceAsStream("database.properties");
System.out.println(in);
Properties pro=new Properties();
pro.load(in);
//获取集合中的键值对
String driverClass=pro.getProperty("driverClass");
String url=pro.getProperty("url");
String username=pro.getProperty("username");
String password=pro.getProperty("password");
Class.forName(driverClass);
Connection con=DriverManager.getConnection(url, username, password);
System.out.println(con);
}
}
5.2 使用DBUtils工具操作数据库
自定义数据库连接类JDBCUtils.java
package cn.itcast.jdbcutil;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
/*
* 编写JDBC的工具类,获取数据库的连接对象采用
* 采用读取配置文件的方式
* 读取文件获取连接,执行一次,采用static代码块,
*
* */
public class JDBCUtilsConfig {
private static Connection con;
private static String driverClass;
private static String url;
private static String username;
private static String password;
static {
try {
readConfig();
Class.forName(driverClass);
con=DriverManager.getConnection(url, username, password);
}catch(Exception e) {
throw new RuntimeException("数据库连接失败");
}
}
private static void readConfig() throws Exception{
InputStream in=JDBCUtilsConfig.class.getClassLoader().getResourceAsStream("database.properties");
Properties pro=new Properties();
pro.load(in);
driverClass=pro.getProperty("driverClass");
url=pro.getProperty("url");
username=pro.getProperty("username");
password=pro.getProperty("password");
}
public static Connection getConnection() {
return con;
}
}
DBUtils增删改数据库
package cn.itcast.demo2;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import cn.itcast.jdbcutil.JDBCUtils;
import cn.itcast.jdbcutil.JDBCUtilsConfig;
/*
* 使用QueryRunner类实现对数据表的insert delete update
* 调用QueryRunner类的方法 update(Connection con,String sql,Object...param)
* Object...param是可变参数,Object类型,sql语句会出现?占位符
*
* */
public class QueryRunnerDemo {
private static Connection con=JDBCUtilsConfig.getConnection();
public static void main(String[] agrs) throws SQLException {
//insert();
// update();
delete();
}
/*
* 定义方法,使用QueryRunner类的方法update向数据表中添加数据
* */
public static void insert() throws SQLException {
//创建QueryRunner类对象
QueryRunner qr=new QueryRunner();
String sql="INSERT INTO sort(sname,sprice,sdesc) VALUES(?,?,?)";
//将三个?占位符的实际参数,写在数组中
Object[] params= {"体育用品",275.32,"购买体育用品"};
//调用QueryRunner类的方法update执行sql语句
int row=qr.update(con,sql,params);
System.out.println(row);
DbUtils.closeQuietly(con);
}
/*
* 定义方法,使用QueryRunner类的方法update将数据表的数据修改
* */
public static void update() throws SQLException {
//创建QuerRunner类对象
QueryRunner qr=new QueryRunner();
//写修改数据的sql语句
String sql="UPDATE sort SET sname=?,sprice=?,sdesc=? WHERE sid=?";
//定义Object数组,存储?中的参数
Object[] params= {"花卉",100.88,"情人节玫瑰花",4};
//调用QueryRunner方法update
int row=qr.update(con,sql,params);
System.out.println(row);
}
/*
* 定义方法,使用QueryRunner类的方法delete将数据表的数据删除
*
* */
public static void delete() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="DELETE FROM sort WHERE sid=?";
int row=qr.update(con, sql,7);
System.out.println(row);
DbUtils.closeQuietly(con);
}
}
DBUtils进行数据库的数据查询
package cn.itcast.demo2;
import java.sql.Connection;
import java.sql.SQLException;
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.ColumnListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.itcast.domain.Sort;
import cn.itcast.jdbcutil.JDBCUtilsConfig;
/*
* QueryRunner数据查询操作:
* 调用QueryRunner类方法query(Connection con,String sql,ResultSetHandler r,Object...params)
* ResultSetHandler r结果集的处理方式,传递ResultSetHandler接口实现类
* Object..params SQL语句中的?占位符
*
* 注意:query方法返回值,返回的是T 泛型,具体返回值类型,跟随结果集处理方式变化
*
*
* */
public class QueryRunnerDemo1 {
private static Connection con=JDBCUtilsConfig.getConnection();
public static void main(String[] args) throws SQLException {
// TODO Auto-generated method stub
// arrayHandler();
// arrayListHandler();
// beanHandler();
// beanListHandler();
// columnListHandler();
// scalarHandler();
// mapHandler();
mapListHandler();
}
/*
* 结果集第一种处理方式:ArrayHandler
* 将结果集的第一行存储到对象数组中 Object[]
* 注意:被封装成数据到JavaBean对象,Sort类必须有空参构造函数,因为query是调用空参构造函数进行初始化的
* */
public static void arrayHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法query执行查询,传递连接对象,sql语句,结果集处理方式的实现类
//返回对象数组
Object[] result=qr.query(con,sql,new ArrayHandler());
for(Object obj:result) {
System.out.print(obj);
}
}
/*
* 结果集第二种处理方法:ArrayListHandler
* 将结果集的每一行封装到对象数组中,出现很多对象数组,对象数组存储到List集合
*
* */
public static void arrayListHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用query方法,结果集处理的参数上,传递实现ArrayListHandler()
List<Object[]>result=qr.query(con, sql, new ArrayListHandler());
for(Object[] objs:result) {
//遍历对象数组
for(Object obj:objs) {
System.out.print(obj+" ");
}
System.out.println();
}
}
/*
* 结果集第三种处理方法:BeanHandler
* 将结果的第一行数据,封装成JavaBean对象
*
* */
public static void beanHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法传递结果集实现类BeanHandler
Sort s=qr.query(con, sql, new BeanHandler<Sort>(Sort.class));
System.out.println(s);
}
/*
* 结果集第四种处理方式,BeanListHandler
* 将数据结果集的每一行数据封装成JavaBean对象
* 多个JavaBean对象封装到List集合中
*
* */
public static void beanListHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法传递结果集的实现类BeanListHandler
List<Sort>list=qr.query(con,sql,new BeanListHandler<Sort>(Sort.class));
for(Sort s: list) {
System.out.println(s);
}
}
/*
* 结果处理第五种方法,ColumnListHandler
* 结果集,指定列的数据,存储到List集合
* List<Object>每个列数据类型不同
*
* */
public static void columnListHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法query,传递结果集实现类ColumnListHandler
//实现类构造方法中,使用字符串的列名
List<Object>list=qr.query(con, sql,new ColumnListHandler<Object>("sname"));
for(Object obj:list) {
System.out.println(obj);
}
}
/*
* 结果集第六种方法,ScalarHandler
* 对于查询后只有一个结果
*
* */
public static void scalarHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用query,传递结果集处理实现类ScalarHandler
Long count=qr.query(con,sql,new ScalarHandler<Long>());
System.out.println(count);
}
/*
* 结果集第七种处理方法,MapHandler
* 将结果集的第一行数据封装到Map集合中
* Map<键,值> 键:列名 值:这列的数据
*
* */
public static void mapHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法query传递结果集实现类MapHandler
//返回值:Map集合,Map接口实现类,泛型
Map<String,Object>map=qr.query(con, sql, new MapHandler());
//遍历Map集合
for(String key:map.keySet()) {
System.out.println(key+".."+map.get(key));
}
}
/*
* 结果集的第八种处理方法,MapListHandler
* 将结果集每一行存储到Map集合,键:列名,值:数据
* Map集合过多,存储到List集合
* */
public static void mapListHandler() throws SQLException {
QueryRunner qr=new QueryRunner();
String sql="SELECT * FROM sort";
//调用方法query,传递结果集实现类MapListHandler
//返回值List集合,存储的是Map集合
List<Map<String,Object>>list=qr.query(con,sql,new MapListHandler());
//遍历集合list
for(Map<String,Object>map:list) {
for(String key:map.keySet()) {
System.out.println(key+"..."+map.get(key));
}
System.out.println();
}
}
}
5.3 dbcp连接池实现数据库的连接
package cn.itcast.demo3;
import java.sql.Connection;
import org.apache.commons.dbcp.BasicDataSource;
public class DataSourceDemo {
/*
* 连接池jar包中定义好一个类BasicDataSource
* 实现类数据源的规范接口javax.sql.DataSource
*
* */
public static void main(String args[]) {
//创建DataSource接口的实现类对象
//实现类
BasicDataSource dataSource=new BasicDataSource();
//连接数据库的4个最基本信息,通过对象方法setXXX设置进来
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybase");
dataSource.setUsername("root");
dataSource.setPassword("123456");
try {
//调用对象方法getConnection获取数据库的连接
Connection con=dataSource.getConnection();
System.out.println(con);
}catch(Exception e) {
throw new RuntimeException("数据库连接失败");
}
}
}
自定义dbcp连接池工具类
JDBCUtils1.java
package cn.itcast.demo3;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
/*
* 自定义dbcp连接池的工具类
*
* */
public class JDBCUtils1 {
//创建出BasicDataSource类对象
private static BasicDataSource datasource=new BasicDataSource();
//静态代码块,对象BasicDataSource对象中的配置,自定义
static {
datasource.setDriverClassName("com.mysql.jdbc.Driver");
datasource.setUrl("jdbc:mysql://localhost:3306/mybase");
datasource.setUsername("root");
datasource.setPassword("123456");
//对象连接池中的连接数量配置
datasource.setInitialSize(10);//初始化的连接数
datasource.setMaxActive(8);//最大连接数
datasource.setMaxIdle(5);//最大空闲数
datasource.setMinIdle(1);//最小空闲数
}
//定义静态方法,返回BasicDataSource类的对象
public static DataSource getDataSource() {
return datasource;
}
}
DBUtils+dbcp连接池实现数据库的操作
package cn.itcast.demo3;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
/*
* 测试写好的工具类
* 提供的是一个DataSource接口的数据源
* QueryRunner类构造方法,接收DataSource接口的实现类
* 后面调用方法updata,query,无需传递他们Connection连接对象
*
*
* */
public class QueryRunnerDemo {
//定义2个方法,实现数据表的添加,数据表查询
//QueryRunner类对象,写在类成员位置
public static void main(String[] args) {
// TODO Auto-generated method stub
// insert();
select();
}
private static QueryRunner qr=new QueryRunner(JDBCUtils1.getDataSource());
//数据表添加数据
public static void insert() {
String sql="INSERT INTO sort(sname,sprice,sdesc) VALUES(?,?,?)";
Object[]params= {"水果",100.12,"刚刚上市的核桃"};
try {
int row=qr.update(sql, params);
System.out.println(row);
}catch(Exception e) {
throw new RuntimeException("数据添加失败");
}
}
//数据表的查询
public static void select() {
String sql="SELECT * FROM sort";
try {
List<Object[]>list=qr.query(sql,new ArrayListHandler());
for(Object[] objs:list) {
for(Object obj:objs) {
System.out.println(obj+"\t");
}
System.out.println();
}
}catch(Exception e){
throw new RuntimeException("查询失败");
}
}
}
自定义连接池
package cn.itcast.demo4;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import cn.itcast.jdbcutil.JDBCUtils;
/*
* 自定义连接池
*
* */
public class MyDataSource implements DataSource {
//1、创建1个容器用于存储Connection对象
private static LinkedList<Connection> pool=new LinkedList<Connection>();
//2、创建5个连接放到容器中去
static {
for(int i=0;i<5;i++) {
Connection conn=JDBCUtils.getConnection();
pool.add(conn);
}
}
@Override
public Connection getConnection() throws SQLException {
// TODO Auto-generated method stub
Connection conn=null;
//3、使用前先判断
if(pool.size()==0) {
//4、池子里面没有我们再创建一些
for(int i=0;i<5;i++) {
conn=JDBCUtils.getConnection();
pool.add(conn);
}
}
//5、从池子里面获取一个连接对象Connection
conn=pool.remove(0);
return conn;
}
/*
* 归还连接对象到连接池中去
* */
public void backConnection(Connection conn) {
pool.add(conn);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
采用装饰器模式自定义连接池
JDBCUtils.java
package cn.itcast.jdbcutil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/*
* 实现JDBC的工具类
* 定义方法,直接返回数据库的连接对象
*
* 定义方法,关闭对象
* */
public class JDBCUtils {
private JDBCUtils() {}
private static Connection con;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/mybase";
String user="root";
String password="123456";
con=DriverManager.getConnection(url,user,password);
}catch(Exception e) {
throw new RuntimeException(e+"数据库连接失败");
}
}
/*
* 定义静态方法,返回数据库的连接对象
* */
public static Connection getConnection() {
return con;
}
public static void close(Connection con,ResultSet rs,Statement stat) {
if(rs!=null) {
try {
rs.close();
}catch(SQLException e) {}
}
if(stat!=null) {
try {
stat.close();
}catch(SQLException e) {}
}
if(con!=null) {
try {
con.close();
}catch(SQLException e) {}
}
}
public static void close(Connection con,Statement stat) {
if(stat!=null) {
try {
stat.close();
}catch(SQLException e) {}
}
if(con!=null) {
try {
con.close();
}catch(SQLException e) {}
}
}
}
MyConnection.java
package cn.itcast.demo4;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/*
* 装饰器模式
*
* */
//1、实现同一个接口Connection
public class MyConnection implements Connection{
//3、定义一个变量
private Connection conn;
private LinkedList<Connection>pool;
//2、编写一个构造方法(参数使用了面向对象的多态性)
public MyConnection(Connection conn,LinkedList<Connection>pool) {
this.conn=conn;
this.pool=pool;
}
//4、书写需要增强的方法
@Override
public void close() throws SQLException {
// TODO Auto-generated method stub
pool.add(conn);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Statement createStatement() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean getAutoCommit() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void commit() throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void rollback() throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean isClosed() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public String getCatalog() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getTransactionIsolation() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public SQLWarning getWarnings() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void clearWarnings() throws SQLException {
// TODO Auto-generated method stub
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setHoldability(int holdability) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getHoldability() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Savepoint setSavepoint() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Clob createClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Blob createBlob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public NClob createNClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public SQLXML createSQLXML() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isValid(int timeout) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
// TODO Auto-generated method stub
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
// TODO Auto-generated method stub
}
@Override
public String getClientInfo(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Properties getClientInfo() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setSchema(String schema) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public String getSchema() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void abort(Executor executor) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getNetworkTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
}
定义连接池
package cn.itcast.demo4;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import cn.itcast.jdbcutil.JDBCUtils;
/*
* 自定义连接池
*
* */
public class MyDataSource1 implements DataSource {
//1、创建1个容器用于存储Connection对象
private static LinkedList<Connection> pool=new LinkedList<Connection>();
//2、创建5个连接放到容器中去
static {
for(int i=0;i<5;i++) {
Connection conn=JDBCUtils.getConnection();
//放入池子中connection对象已经经过改造了
MyConnection myconn=new MyConnection(conn,pool);
pool.add(myconn);
}
}
@Override
public Connection getConnection() throws SQLException {
// TODO Auto-generated method stub
Connection conn=null;
//3、使用前先判断
if(pool.size()==0) {
//4、池子里面没有我们再创建一些
for(int i=0;i<5;i++) {
conn=JDBCUtils.getConnection();
//放入池子中connection对象已经经过改造了
MyConnection myconn=new MyConnection(conn,pool);
pool.add(myconn);
}
}
//5、从池子里面获取一个连接对象Connection
conn=pool.remove(0);
return conn;
}
/*
* 归还连接对象到连接池中去
* */
public void backConnection(Connection conn) {
pool.add(conn);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
5.4 C3P0连接池(常用,因为它只要修改配置就可以轻松的更换数据库以及用户)
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///mybase</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="ctgu">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///mybase</property>
<property name="user">root</property>
<property name="password">123456</property>
</named-config>
</c3p0-config>
package cn.itcast.C3P0;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
private static ComboPooledDataSource dataSource=new ComboPooledDataSource();//使用的默认配置
//private static ComboPooledDataSource dataSource=new ComboPooledDataSource("ctgu");//使用的自定义配置
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
try {
return dataSource.getConnection();
}catch(SQLException e) {
throw new RuntimeException(e);
}
}
}
案例应用——管家婆记账软件
常用的项目分析逻辑
view层作用: 视图层,即项目中的界面
controller层作用: 控制层, 获取界面上的数据,为界面设置数据; 将要实现的功能交给业务层处理
service层作用: 业务层, 功能的实现, 与controller控制层和数据访问层DAO交互, 将对数据库的操作交给DAO数据访问层来处理
dao层作用: 数据访问层, 用来操作数据库表的数据
db数据库: 这里指MySQL
domain 实体包: 存放JavaBean
tools工具包:存放项目中使用到的工具类
test 测试包: 存放项目功能测试的代码
功能界面菜单
界面菜单的完成,是项目编写的第一步。
我们通过输出语句,完成界面菜单的输出,之后再根据输入的功能序号,进行对应功能的调用执行。
功能实现步骤
1编写MainView类run方法
1.1完成功能界面菜单显示
1.2接收键盘输入的功能选项
1.3根据选项值,调用对应的功能方法
2编写MainApp类的main主方法
2.1调用MainView类中run方法,实现将程序执行起来,显示功能界面菜单。
MainApp.java
package cn.ctgu.gjp.app;
import cn.ctgu.gjp.view.MainView;
/*
* 主程序类:开启软件安程序
* */
public class MainApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
new MainView().run();
}
}
MainView.java
package cn.ctgu.gjp.view;
import java.util.List;
import java.util.Scanner;
import cn.ctgu.gjp.controller.ZhangWuController;
import cn.ctgu.gjp.domain.ZhangWu;
/*
* 视图层,用户看到和操作的界面
* 数据传递给controller层实现
* 成员位置:创建controller对象
*
* */
public class MainView {
private ZhangWuController controller=new ZhangWuController();
/*
* 实现界面效果
* 接收用户的输入
* 根据数据,调用不同的功能方法
*
* */
public void run() {
/*
* 创建Scanner类对象,反复键盘输入
* */
Scanner sc=new Scanner(System.in);
while(true) {
System.out.println("-------管家婆家庭记账软件--------");
System.out.println("1.添加账务 2.编辑账务 3.删除账务 4.查询账务 5.退出系统");
System.out.println("请输入要操作的功能序号[1-5]:");
//接受用户的菜单选择
int choose=sc.nextInt();
//对选择的菜单判断,调用不同的功能
switch(choose) {
case 1:
//选择添加账务,调用添加账务的方法
addZhangWu();
break;
case 2:
//选择编辑账务,调用编辑账务的方法
editZhangWu();
break;
case 3:
//选择删除账务,调用删除账务的方法
deleteZhangWu();
break;
case 4:
//选择查询账务,调用查询账务的方法
selectZhangWu();
break;
case 5:
System.exit(0);
break;
}
}
}
/*
* 定义方法实现对账务的删除
* 实现思想:
* 接收用户的输入,输入一个主键数据
* 调用控制层,传递一个主键
*
* */
public void deleteZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项进行修改
selectAll();
System.out.println("选择的是删除功能,请输入ID号:");
int zwid=new Scanner(System.in).nextInt();
//调用控制层方法,传递主键id即可
controller.deleteZhangWu(zwid);
System.out.println("删除账务成功");
}
/*
* 定义方法,实现对账务的编辑功能
* 实现思想:
* 接收用户的输入
* 数据的信息,封装成ZhangWu对象
* 调用控制层的方法,传递ZhangWu对象,实现编辑
*
* */
public void editZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项进行修改
selectAll();
System.out.println("选择的是编辑功能,请输入数据");
Scanner sc=new Scanner(System.in);
//接收用户的数据
System.out.println("输入ID:");
int zwid=sc.nextInt();
System.out.println("输入分类名称:");
String flname=sc.next();
System.out.println("输入金额:");
double money=sc.nextDouble();
System.out.println("输入账户:");
String zhanghu=sc.next();
System.out.println("输入日期:格式XXX-XX-XX");
String createtime=sc.next();
System.out.println("输入具体描述:");
String description=sc.next();
//将所有用户输入的数据封装到ZhangWu对象中
//输入的ID,必须封装对象
ZhangWu zw=new ZhangWu(zwid, flname, money, zhanghu, createtime, description);
//调用controller层中的方法,实现编辑账务
controller.editZhangWu(zw);
System.out.println("账务编辑成功!");
}
/*
* 定义方法 addZhangWu
* 添加账务的方法,用户在界面中选择菜单1的时候调用
* 实现思想:
* 接收键盘输入,5项输入,调用controller层方法
* */
public void addZhangWu() {
System.out.println("选择的添加账务功能,请输入一下内容");
Scanner sc=new Scanner(System.in);
System.out.println("输入分类名称:");
String flname=sc.next();
System.out.println("输入金额:");
double money=sc.nextDouble();
System.out.println("输入账户:");
String zhanghu=sc.next();
System.out.println("输入日期:格式XXX-XX-XX");
String createtime=sc.next();
System.out.println("输入具体描述:");
String description=sc.next();
//将接收到的数据调用controller层的方法,传递参数实现数据添加
ZhangWu zw=new ZhangWu(0, flname, money, zhanghu, createtime, description);
controller.addZhangWu(zw);
System.out.println("添加账务成功!");
}
/*
* 定义方法selectZhangWu()
* 显示查询的方式1所有查询 2条件查询
*
* */
public void selectZhangWu() {
System.out.println("1.查询所有 2.条件查询");
Scanner sc=new Scanner(System.in);
int selectChooser=sc.nextInt();
//判断根据用户的选择,调用不同的功能
switch(selectChooser) {
case 1:
//选择的查询所有,调用查询所有的方法
selectAll();
break;
case 2:
//选择条件查询,调用带有查询条件的方法
select();
break;
}
}
/*
* 定义方法实现查询所有的账务数据
* */
public void selectAll() {
//调用控制层中的方法,查询所有的账务数据
List<ZhangWu>list=controller.selectAll();
print(list);
}
/*
* 定义方法实现条件查询账务数据
* 提供用户的输入日期,开始日期结束日期
* 就2个日期,传递到controller层
* 调用controller的方法,传递2个日期参数
* 获取到controller查询的结果集,打印出来
* */
public void select() {
System.out.println("选择条件查询,输入日期格式XXXX-XX-XX");
Scanner sc=new Scanner(System.in);
System.out.println("请输入开始日期:");
String startDate=sc.nextLine();
System.out.println("请输入结束日期:");
String endDate=sc.nextLine();
//调用controller层的方法,传递日期,获取查询结果集
List<ZhangWu>list=controller.select(startDate, endDate);
if(list.size()!=0)
print(list);
else
System.out.println("没有查询到数据");
}
//输出账务数据方法,接收List集合,遍历集合,输出表格
private void print(List<ZhangWu> list) {
//输出表头
System.out.println("ID\t类别\t账户\t金额\t时间\t说明");
//遍历集合,结果输出控制台
for(ZhangWu zw:list) {
System.out.println(zw.getZwid()+"\t"+zw.getFlname()+"\t"+zw.getZhanghu()+"\t"+
zw.getMoney()+"\t"+zw.getCreatetime()+"\t"+zw.getDescription());
}
}
}
查询所有账务
功能实现步骤
1编写MainView类中selectZhangWu方法
1.1通过输出语句,显示出要查询账务的方式
1.2接收键盘的输入项,调用对应的方法(1.查询所有 2.按条件查询)
2编写MainView类中selectAll查询所有账务方法
2.1调用ZhangWuService类selectAll方法,返回包含所有账务数据的List集合
2.2调用MainView类中print方法,实现控制台显示所有账务数据
3编写MainView类中print方法
3.1使用输出语句,打印出账务表的表头名称
3.2遍历账务集合,将每个账务信息输出打印
4编写ZhangWuService类中selectAll方法
4.1调用ZhangWuDao类中selectAll方法,返回包含所有账务数据的List集合
5编写ZhangWuDao类中selectAll()方法
5.1通过QueryRunner对象,调用query方法查询数据库表gjp_zhangwu,返回包含所有账务数据的List集合
多条件查询账务
功能分析
1编写MainView类中select方法
1.1通过键盘输入查询日期的范围
1.2调用ZhangWuSerice类中select方法,返回查询日期范围内的账务信息集合List
1.3调用MainView类中的print方法,将账务信息集合中的内容显示在控制台中
2编写ZhangWuService类中select方法
2.1调用ZhangWuDao 类中select方法,返回查询日期范围内的账务信息集合List
3编写ZhangWuDao类中select方法
通过QueryRunner对象,调用query方法查询数据库表gjp_zhangwu,返回包含查询日期范围内的账务数据List集合
ZhangWuService.java
package cn.ctgu.gjp.service;
import java.util.List;
import cn.ctgu.gjp.dao.ZhangWuDao;
import cn.ctgu.gjp.domain.ZhangWu;
/*
* 业务层类
* 接收上一层,控制层controller的数据
* 经过计算,传递给dao层,操作数据库
* 调用dao层中的类,类成员位置,创建dao类对象
*
* */
public class ZhangWuService {
private ZhangWuDao dao=new ZhangWuDao();
/*
* 定义方法,实现编辑账务
* 由控制层调用,传递ZhangWu对象
* 调用dao层的方法,传递ZhangWu对象
* */
public void editZhangWu(ZhangWu zw) {
dao.editZhangWu(zw);
}
/*
* 定义方法,实现添加账务
* 是由控制层调用,传递ZhangWu类型对象
* 调用dao层方法,传递ZhangWu对象
*
* */
public void addZhangWu(ZhangWu zw) {
dao.addZhangWu(zw);
}
/*
* 定义方法,实现条件查询账务
* 方法由控制层调用,传递2个日期字符串
* 调用dao层的方法,传递2个日期字符串
* 获取到查询结果集
*
* */
public List<ZhangWu>select(String startDate,String endDate){
return dao.select(startDate,endDate);
}
/*
* 定义方法,实现查询所有的账务数据
* 此方法由控制层调用,去调用dao层的方法
* 返回存储账务的list集合
* */
public List<ZhangWu> selectAll() {
return dao.selectAll();
}
public void deleteZhangWu(int zwid) {
// TODO Auto-generated method stub
dao.deleteZhangWu(zwid);
}
}
ZhangWuDao.java
package cn.ctgu.gjp.dao;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import cn.ctgu.gjp.domain.ZhangWu;
import cn.ctgu.gjp.tools.JDBCUtils;
/*
* 实现对数据表gjp_zhangwu数据增删改查操作
* dbutils工具类完成,类成员创建QueryRunnner对象,指定数据源
*
* */
public class ZhangWuDao {
private QueryRunner qr=new QueryRunner(JDBCUtils.getDataSource());
/*
* 定义方法,实现添加账务功能
* 由业务层调用,传递ZhangWu对象
* 将ZhangWu对象中的数据,添加到数据表
* */
public void addZhangWu(ZhangWu zw) {
try {
//拼写添加数据的sql
String sql="INSERT INTO gjp_zhangwu(flname,money,zhanghu,createtime,description)VALUES(?,?,?,?,?)";
//创建对象数组,存储5个占位符的实际参数
//实际参数来源是传递过来的对象的ZhangWu
Object[]params= {zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription()};
//调用qr对象中的方法update执行添加
qr.update(sql,params);
}catch(SQLException e) {
System.out.println(e);
throw new RuntimeException("账务添加失败");
}
}
/*
* 定义方法,查询数据库,带有条件去查询账务表
* 由业务层调用,查询结果集存储到Bean对象,存储到List集合
* 调用者传递2个日期字符串
*
* */
public List<ZhangWu>select(String startDate,String endDate){
try {
//拼写条件查询的sql语句
String sql="SELECT * FROM gjp_zhangwu WHERE createtime BETWEEN ? AND ?";
//定义对象数组,存储?占位符
Object[]params= {startDate,endDate};
//调用qr对象的方法query查询数据表,获取结果集
return qr.query(sql, new BeanListHandler<ZhangWu>(ZhangWu.class),params);
}catch(SQLException e) {
System.out.println(e);
throw new RuntimeException("条件查询失败");
}
}
/*
* 定义方法,查询数据库,获取所有的账务数据
* 方法由业务层调用
* 结果集将所有的账务数据存储到Bean对象中,然后存储到集合中
*
* */
public List<ZhangWu> selectAll() {
try {
//查询账务数据的sql语句
String sql="SELECT * FROM gjp_zhangwu";
//调用qr对象的方法,query方法,结果集BeanListHandler
List<ZhangWu>list=qr.query(sql, new BeanListHandler<>(ZhangWu.class));
return list;
}catch(Exception e) {
System.out.println(e);
throw new RuntimeException("查询所有账务失败");
}
}
/*
* 定义方法实现编辑账务功能
* 由业务层调用传递ZhangWu对象
* 将对象中的数据更新到数据表
* */
public void editZhangWu(ZhangWu zw) {
// TODO Auto-generated method stub
try {
//更新数据的sql
String sql="UPDATE gjp_zhangwu SET flname=?,money=?,"
+ "zhanghu=?,createtime=?,description=? WHERE zwid=?";
//定义对象数组,将所有的参数放进去
Object[]params= {zw.getZwid(),zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription()};
//调用qr对象方法update执行更新
qr.update(sql,params);
}catch(SQLException e) {
System.out.println(e);
throw new RuntimeException("账务编辑失败");
}
}
public void deleteZhangWu(int zwid) {
// TODO Auto-generated method stub
try {
//删除数据的sql
String sql="DELETE FROM gjp_zhangwu WHERE zwid=?";
qr.update(sql,zwid);
}catch(SQLException e) {
System.out.println(e);
throw new RuntimeException("删除账务失败");
}
}
}
添加账务
功能分析
1编写MainView类中addZhangWu方法
1.1键盘输入新添加的账务信息
1.2调用ZhangWuService类中addZhangWu方法,用来指定账务的添加
1.3添加完毕后,使用输出语句,提示“添加账务成功!”
2编写ZhangWuService类中addZhangWu方法
2.1调用ZhangWuDao类中addZhangWu方法,用来指定账务的添加
3编写ZhangWuDao类中addZhangWu方法
3.1通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成指定账务添加到数据库表中
编辑账务
功能分析
1编写MainView类中editZhangWu方法
1.1键盘输入要编辑的账务信息ID号
1.2键盘输入要修改的账务信息内容
1.3调用ZhangWuService类中editZhangWu方法,用来将指定的账务信息进行更新
1.4更新完毕后,使用输出语句,提示 “编辑账务成功!”
2编写ZhangWuService类中editZhangWu方法
2.1调用ZhangWuDao类中editZhangWu方法,用来将指定的账务信息进行更新
3编写ZhangWuDao类中editZhangWu方法
3.1通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成数据库表中指定账务更新操作
删除账务
功能分析
1编写MainView类中deleteZhangWu方法
1.1键盘输入要删除的账务信息ID号
1.2调用ZhangWuService类中deleteZhangWu方法,用来将指定的账务信息删除
1.3删除完毕后,使用输出语句,提示 “删除账务成功!”
2编写ZhangWuService类中deleteZhangWu方法
2.1调用ZhangWuDao类中deleteZhangWu方法,用来将指定的账务信息删除
3编写ZhangWuDao类中deleteZhangWu方法
3.1通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成数据库表中指定账务删除操作
其他代码:
ZhangWuController.java
package cn.ctgu.gjp.controller;
import java.util.List;
import cn.ctgu.gjp.domain.ZhangWu;
import cn.ctgu.gjp.service.ZhangWuService;
/*
* 控制器层
* 接收视图层的数据,数据传递给service层
* 成员位置,创建安service对象
*
*
* */
public class ZhangWuController {
private ZhangWuService service=new ZhangWuService();
/*
* 定义方法实现删除功能
* 由视图层调用,传递int类型主键
* 调用service层方法,传递int主键
*
* */
public void deleteZhangWu(int zwid) {
service.deleteZhangWu(zwid);
}
/*
* 定义方法实现编辑账务功能
* 由视图层调用,传递参数,也是ZhangWu对象
* 调用Service层的方法,传递ZhangWu对象
* */
public void editZhangWu(ZhangWu zw) {
service.editZhangWu(zw);
}
/*
* 定义方法,实现账务添加功能
* 由视图层调用,传递参数(传递过来的参数不能是5个数据,传递的是1个ZhangWu类型的对象)
* 方法调用service层的方法,传递ZhangWu对象,获取到添加后的结果集(添加成功的行数 int)
* */
public void addZhangWu(ZhangWu zw) {
service.addZhangWu(zw);
}
/*
* 定义方法,实现条件查询账务
* 方法由视图层调用,传递两个日期的字符串
* 调用service层的方法,传递两个日期字符串,获取结果集
* 结果集返回给视图
*
*
* */
public List<ZhangWu>select(String startDate,String endDate){
return service.select(startDate, endDate);
}
/*
* 控制层类定义方法,实现查询所有的账务数据
* 方法由视图层调用,方法调用service层
* */
public List<ZhangWu> selectAll() {
return service.selectAll();
}
}
ZhangWu.java(domain包中的JavaBean)
package cn.ctgu.gjp.domain;
public class ZhangWu {
private int zwid;
private String flname;
private double money;
private String zhanghu;
private String createtime;
private String description;
public ZhangWu(int zwid, String flname, double money, String zhanghu, String createtime, String description) {
super();
this.zwid = zwid;
this.flname = flname;
this.money = money;
this.zhanghu = zhanghu;
this.createtime = createtime;
this.description = description;
}
public int getZwid() {
return zwid;
}
public void setZwid(int zwid) {
this.zwid = zwid;
}
public String getFlname() {
return flname;
}
public void setFlname(String flname) {
this.flname = flname;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getZhanghu() {
return zhanghu;
}
public void setZhanghu(String zhanghu) {
this.zhanghu = zhanghu;
}
public String getCreatetime() {
return createtime;
}
public void setCreatetime(String createtime) {
this.createtime = createtime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public ZhangWu() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Zhangwu [zwid=" + zwid + ", flname=" + flname + ", money=" + money + ", zhanghu=" + zhanghu
+ ", createtime=" + createtime + ", description=" + description + "]";
}
}
JDBCUtils.java(tools包中的工具类)
package cn.ctgu.gjp.domain;
public class ZhangWu {
private int zwid;
private String flname;
private double money;
private String zhanghu;
private String createtime;
private String description;
public ZhangWu(int zwid, String flname, double money, String zhanghu, String createtime, String description) {
super();
this.zwid = zwid;
this.flname = flname;
this.money = money;
this.zhanghu = zhanghu;
this.createtime = createtime;
this.description = description;
}
public int getZwid() {
return zwid;
}
public void setZwid(int zwid) {
this.zwid = zwid;
}
public String getFlname() {
return flname;
}
public void setFlname(String flname) {
this.flname = flname;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getZhanghu() {
return zhanghu;
}
public void setZhanghu(String zhanghu) {
this.zhanghu = zhanghu;
}
public String getCreatetime() {
return createtime;
}
public void setCreatetime(String createtime) {
this.createtime = createtime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public ZhangWu() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Zhangwu [zwid=" + zwid + ", flname=" + flname + ", money=" + money + ", zhanghu=" + zhanghu
+ ", createtime=" + createtime + ", description=" + description + "]";
}
}
5.5 数据库的事务
1、什么是事务?
一件事情有n个组成单元,要不这个n个组成单元同时成功,要不n个单元就同时失败
也就是将n个组成单元放到一个事务中。
2、Mysql的事务
默认的事务:一条sql语句就是一个事务,默认就开启事务并提交事务
手动事务:
1、显示的开启一个事务:start transaction
2、事务提交:commit代表从开启事务到事务提交中间的所有的sql都认为有效
真正的更新事务:
3、事务的回滚:rollback代表事物的回滚,从开启事务到事务回滚,中间的所有的
sql操作都认为无效数据库,即没有被更新
总结:
Mysql的事务控制:
开启事务:start transaction
提交事务:commit
回滚事务:rollback
JDBC事务控制:
开启事务:conn.setAutoCommit(false);
提交事务:conn.commit();
回滚事务:conn.rollback()
DBUtils的事务控制也是通过jdbc
ThreadLocal:实现的是通过线程绑定的方式传递参数
1.事务的特性ACID
1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
2.并发访问问题—-由隔离性引起
如果不考虑隔离性,事务存在3中并发访问问题。
1)脏读:B事务读取到了A事务尚未提交的数据 —— 要求B事务要读取A事 务提交的数据
2)不可重复读:一个事务中 两次读取的数据的内容不一致 —– 要求的是一个事 务中多次读取时数据是一致的 — unpdate
3)幻读/虚读:一个事务中 两次读取的数据的数量不一致 —– 要求在一个事务多 次读取的数据的数量是一致的 –insert delete
3.事务的隔离级别
1)read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决
2)read committed:读取已经提交的数据 :可以解决脏读 —- oracle默认的
3)repeatable read:重读读取:可以解决脏读 和 不可重复读 —mysql默认的
serializable:串行化:可以解决 脏读 不可重复读 和 虚读—相当于锁表
查看mysql数据库默认的隔离级别:select @@tx_isolation
设置mysql的隔离级别:set session transaction isolation level 设置事务隔离级别
隔离级别的性能:
read uncommitted>read committed>repeatable read>serialazable
安全性:read uncommitted<read committed<repeatable read<serialazable
JDBC控制事务
package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo {
public static void main(String[] args) {
//通过jdbc去控制事务
Connection conn=null;
try {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获得Connection
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mybase", "root", "123456");
//手动开启事务
conn.setAutoCommit(false);//手动提交
//3、获得执行平台
Statement stmt=conn.createStatement();
//4、操作sql
stmt.executeUpdate("insert into product values(9,'早餐','25','吃早饭')");
//提交事务
//执行sql的connection与开启事务的connection必须是同一个才能对事务进行控制
conn.commit();
stmt.close();
conn.close();
}catch(Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
DBUtils工具控制事务
package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import cn.itcast.demo3.JDBCUtils1;
import cn.itcast.jdbcutil.JDBCUtilsConfig;
public class DBUtilsDemo {
public static void main(String[] args) {
Connection conn=null;
try {
QueryRunner qr=new QueryRunner();
//获得一个Connection
conn=JDBCUtilsConfig.getConnection();
//开启事务
conn.setAutoCommit(false);
qr.update(conn, "update product set sprice=100 where sid=8");
//提交回滚事务
conn.commit();
}catch(SQLException e) {
try {
conn.rollback();
}catch(SQLException e1) {
e1.printStackTrace();
}
}
}
}
事务隔离案例——转账
transfer.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/transferServlet" method="post">
转出账户:<input type="text" name="out"/><br/>
转入账户:<input type="text" name="in"/><br/>
转账金额:<input type="text" name="money"/>
<input type="submit" value="确认转账"/>
</form>
</body>
</html>
transferServlet.java
package cn.ctgu.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.ctgu.service.TransferService;
/**
* Servlet implementation class transferServlet
*/
@WebServlet("/transferServlet")
public class transferServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收转账的参数
String out=request.getParameter("out");
String in=request.getParameter("in");
String moneyStr=request.getParameter("money");
double money=Double.parseDouble(moneyStr);
//调用业务层的转账方法
TransferService service=new TransferService();
boolean isTransferSuccess=service.transfer(out,in,money);
response.setContentType("text/html;charset=utf-8");
if(isTransferSuccess) {
response.getWriter().write("转账成功!!!");
}else {
response.getWriter().write("转账失败!!!");
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
TransferService.java
package cn.ctgu.service;
import java.sql.Connection;
import java.sql.SQLException;
import cn.ctgu.dao.JDBCUtils;
import cn.ctgu.dao.TransferDao;
public class TransferService {
public boolean transfer(String out,String in,double money) {
boolean transfersuccess=true;
TransferDao dao=new TransferDao();
Connection conn=null;
try {
conn=JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//转入账户
dao.out(conn,out,money);
//转出账户
dao.in(conn,in,money);
}catch(Exception e) {
transfersuccess=false;
//回滚事务
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
throw new RuntimeException("转账失败");
}
}
finally {
try {
conn.commit();//提交事务
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
throw new RuntimeException("转账失败");
}
}
return transfersuccess;
}
}
TransferDao.java
package cn.ctgu.dao;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
public class TransferDao {
public void out(Connection conn,String out,double money) throws SQLException {
QueryRunner qr=new QueryRunner();
Object[]params= {money,out};
String sql= "UPDATE counts SET money=money-? WHERE cname=?";
qr.update(conn,sql,params);
}
public void in(Connection conn,String in,double money) throws SQLException {
QueryRunner qr=new QueryRunner();
Object[]params= {money,in};
String sql="UPDATE counts SET money=money+? WHERE cname=?";
qr.update(conn,sql,params);
}
}
通过 ThreadLocal改进的代码(推荐这种)
TransferService2.java
package cn.ctgu.service;
import java.sql.Connection;
import java.sql.SQLException;
import cn.ctgu.dao.JDBCUtils;
import cn.ctgu.dao.MyDataSourceUtils;
import cn.ctgu.dao.TransferDao2;
public class TransferService2 {
public boolean transfer(String out,String in,double money) {
boolean transfersuccess=true;
TransferDao2 dao=new TransferDao2();
try {
//开启事务
MyDataSourceUtils.startTransaction();
//转入账户
dao.out(out,money);
//转出账户
dao.in(in,money);
}catch(Exception e) {
transfersuccess=false;
//回滚事务
try {
MyDataSourceUtils.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
throw new RuntimeException("转账失败");
}
}
finally {
try {
MyDataSourceUtils.commit();//提交事务
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
throw new RuntimeException("转账失败");
}
}
return transfersuccess;
}
}
MyDataSourceUtils.java(关键代码,将一个连接放到一个线程中)
package cn.ctgu.dao;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class MyDataSourceUtils {
//获得Connection 从连接池中获取
private static ComboPooledDataSource dataSource=new ComboPooledDataSource();
//创建ThreadLocal
private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
//开启事务
public static void startTransaction() throws SQLException {
Connection conn=getCurrentConnection();
conn.setAutoCommit(false);
}
//获得当前线程绑定的conn
public static Connection getCurrentConnection() throws SQLException {
//从ThreadLocal寻找当前线程是否有对应Connection
Connection conn=tl.get();
if(conn==null) {
//获得新的connection
conn= getConnection();
//将conn资源绑定到ThreadLocal(map)上
tl.set(conn);
}
return conn;
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//回滚事务
public static void rollback() throws SQLException {
// TODO Auto-generated method stub
getCurrentConnection().rollback();
}
//提交事务
public static void commit() throws SQLException {
// TODO Auto-generated method stub
Connection conn=getCurrentConnection();
conn.commit();
//将Connection从ThreadLocal中移除
tl.remove();
conn.close();
}
}
TransferDao2.java
package cn.ctgu.dao;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
public class TransferDao2 {
public void out(String out,double money) throws SQLException {
QueryRunner qr=new QueryRunner();
Connection conn=MyDataSourceUtils.getCurrentConnection();
Object[]params= {money,out};
String sql= "UPDATE counts SET money=money-? WHERE cname=?";
qr.update(conn,sql,params);
}
public void in(String in,double money) throws SQLException {
QueryRunner qr=new QueryRunner();
Connection conn=MyDataSourceUtils.getCurrentConnection();
Object[]params= {money,in};
String sql="UPDATE counts SET money=money+? WHERE cname=?";
qr.update(conn,sql,params);
}
}