JavaWeb——数据库(Mysql)

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 表名 set1=值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
/*
havingwhere的区别:
    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);
     }
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值