JDBC,个人学习笔记

一、引言

1.1 如何操作数据库

使用客户端工具访问数据库,需要手工建立连接,输入用户名和密码登陆,编写SQL语句,点击执行,查看操作结果(结果集或受影响行数)

1.2 实际开发中,会采用客户端操作数据库吗?

在实际开发中,当用户的数据发生改变时,不可能通过客户端操作执行SQL语句,因为操作量过大,无法保证效率和正确性。

二、JDBC (Java Database Connectivity)

2.1 什么是JDBC?

JDBC (Java Database Connectivity) java连接数据库,可以使用java语言连接数据库完成CRUD操作。

2.2 JDBC核心sixiang

java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver数据库驱动)。

2.2.1 MySQL数据库驱动

mysql-connector-java-5.1X 适用于5.X版本
mysql-connector-java-8.0X 适用于8.X版本

2.2.2 JDBC API

JDBC是由多个接口和类进行功能实现。
class java.sql.DriverManager 管理多个数据库驱动类,提供了获取数据库连接的方法
interface java.sql.Connection 代表一个数据库连接(当connection不是null,表示已连接数据库)
interface java.sql.Statement 发送SQL语句到数据库工具
interface java.sql.ResultSet 保存SQL查询语句的结果数据(结果集)
class java.sql.SQLException 处理数据库应用程序时所发生的异常

2.3 环境搭建

1.在项目下新建lib文件夹,用于存放jar文件
2.将mysql驱动mysql-connector-java-5.1X复制到项目的lib文件夹中
3.选中lib文件夹右键Add as Library,点击OK

三、JDBC开发步骤

3.1 注册驱动

使用Class.forName(“com.mysql.jdbc.Driver”);手动加载字节码文件到JVM中
Class.forName(‘com.mysql.jdbc.Driver’);//加载驱动

3.2 连接数据库

通过 DriverManager.getConnection(url,user,password) //获取数据库连接对象
URL:jdbc:mysql://localhost:3306/database
username:root
password:123456
Connection conn=DriverManager.getConnection(“jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8”,“root”,“123456”);
URL统一资源定位符:由协议、IP、端口、SID(程序实例名称)组成。

3.3 获取发送SQL的对象

//通过Connection对象获得Statement对象,用于对数据库进行通用访问
Statement statement=conn.createStatement();

3.4 执行SQL语句

// 执行SQL语句并接收执行结果

String sql="INSERT INTO t_jobs(JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY) VALUES('JAVA_Le','JAVA_LEcturer',4000,10000);";
int result=statement.executeUpdate(sql);

注意:
在编写DML语句时,一定要注意字符串参数的符号是单引号’值’
DML语句:增删改时,返回受影响行数(int类型)
DQL语句:查询时,返回结果数据(ResultSet结果集)
增删改:executeUpdate()

3.5 处理结果

接受处理操作结果

if(result==1){
	System.out.println("Success");
}

注意:
受影响函数:逻辑判断,方法返回
查询结果:迭代、依次获取

3.6 释放资源

遵循先开后关原则,释放所使用到的资源对象
statement.close();
conn.close();

四、Result(结果集)

在执行查询SQL后,存放查询到的结果集数据

4.1 接收结果集
ResultSet rs=statement.executeQuery(sql);
Result rs=statement.executeQuery("SELECT * FROM t_employee;");
4.2 遍历ResultSet中的数据

Result 以表(table)结构进行临时结果的存储,需要通过JDBC API将其中数据进行依次获取。
数据行指针:初始位置在第一行数据前,每调用一次boolean next()方法,ResultSet的指针向下移动一行,结果为true,表示当前行数据
rs.getXxx(整数):代表根据列的编号顺序获得,从1开始
rs.getXxx(“列名”):代表根据列名获得。
boolean next() throws SQLException //判断rs结果集中下一行是否存在数据

4.2.1 遍历方法

int getInt(int columnIndex) throws SQLException; //获得当前行第N列的int值
int getInt(String columnLable) throws SQLException; //获得当前行columnLable列的int值
double getDouble(int columnIndex) throws SQLException; //获得当前行第N列的double值
double getDouble(String columnLable) throws SQLException; //获得当前行columnLable列的double值
String getString(int columnIndex) throws SQLException; //获得当前行第N列的String值
String getString(String columnLable) throws SQLException; //获得当前行columnLable列的String值
注意:列的编号从1开始。

4.2.2 根据列的编号获取数据
while (resultSet.next()){
	String job_id =resultSet.getString(1);
	String job_title=resultSet.getString(2);
	String min_salary=resultSet.getString(3);
	String max_salary=resultSet.getString(4);
	System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);
}

五、常见错误

java.lang.ClassNotFoundException; //找不到类(类名书写错误,没有导入jar包)
java.lang.SQLException; //与SQL语句相关的错误(约束错误、表名列名书写错误) 建议:在客户端工具中测试SQL语句之后再粘贴在代码中
com.mysql.jdbc.exception.jdbc4.MySQLSyntaxErrorException:Unknown column //原因:列值String类型没有加单引号
Duplicate entry ‘1’ for key ‘PRIMARY’ //原因:主键值已存在或混乱,更改主键值或清空表
com.mysql.jdbc.exception.jdbc4.MySQLSyntaxException:Unknow column ‘password’ in //原因:可能输入的值的类型不对,确定是否插入的元素时对应的值的类型正确

六、综合案例【登录】

6.1 创建表

创建一张用户表user
id,主键,自动增长
用户名,字符串类型,非空
密码,字符串类型,非空
手机号码,字符串类型
插入2条测试语句

6.2 实现登录

通过控制台用户输入用户名和密码
用户输入的用户名和密码作为条件,编写查询SQL语句
如果该用户存在,提示登录成功,反之提示失败

七、SQL注入问题

7.1 什么是SQL注入

用户输入的护具中有SQL关键字或语法并且参与了SQL语句的编译;导致SQL语句编译后的条件含义为true,一直得到正确的结果。这种现象称为SQL注入。

7.2 如何避免SQL注入

由于编写的SQL语句是在用户输入数据,整合后再进行编译。所以为了避免SQL注入的问题,我们要使SQL语句在用户输入数据前就已进行
编译成完整的SQL语句,再进行填充数据。

八、PreparedStatement【重点】

PreparedStatement继承了Statement接口,所以执行SQL语句的方法无异。

8.1 PreparedStatement的应用

作用:
1、预编译SQL语句,效率高
2、安全,避免SQL注入
3、可以动态的填充数据,执行多个同构的SQL语句

8.1.1 参数标记

//预编译SQL语句
PreparedStatement pstmt=conn.prepareStatement(“SELECT * FROM t_users WHERE username=? and password=?”);
注意:JDBC中的所有参数都由?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。

8.1.2 动态参数绑定

pstmt.setXxx(下标,值) 参数下标从1开始,为指定参数下标绑定值
//预编译SQL语句
PreparedStatement pstmt=conn.prepareStatement(“SELECT * FROM t_users WHERE username=? and password=?”);
//为参数下标赋值
pstmt.setString(1,username);
pstmt.setString(2,password);

九、封装工具类

在实际JDBC的使用中,存在着大量的重复代码:例如连接数据库,关闭数据库等这些操作
我们需要把传统的JDBC代码进行重构,抽取除通用的JDBC工具类!以后连接任何数据库、释放资源都可以使用这个工具类。

9.1 重用性方案

封装获取连接、释放资源两个方法。
提供public static Connection getConnection(){}方法
提供public static void closeAll(Connection conn,Statement sm,ResultSet rs){}方法

9.1.1 重用工具类实现
public class DBUtils {
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
    //1获取连接
    public static Connection getConnection(){
        Connection connection=null;
        try {
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb","root","123456");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  connection;
    }
    //2释放资源
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
        try {
            if(resultSet!=null){
                resultSet.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
9.2 跨平台方案

定义:public static final Properties prop=new Properties(); //读取配置文件的Map
定义:static{
//首次使用工具类时,加载驱动
InputStream is=JDBCUtil.class.getResourceAsStream(“路径”); //通过复用本类自带流,读取jdbc.properties配置文件。classPath=bin
prop.load(is); //通过prop对象将流中的配置信息分割成键值对
String driverName=prop.getProperty(“driver”); //通过driverName的键值获取对应的值(com.mysql.jdbc.Driver)
Class.forName(driverName); //加载驱动
}

9.2.1 跨平台工具类实现

在src目录下新建db.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mudb3
user=root
password=123456

public class DBUtils {
    private static final Properties PROPERTIES=new Properties();//存储配置文件的map
    static {
        InputStream is=DBUtils.class.getResourceAsStream("/db.properties");
        try {
            PROPERTIES.load(is);
            Class.forName(PROPERTIES.getProperty("driver"));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection(){
        Connection connection=null;
        try {
            connection= DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("username"),PROPERTIES.getProperty("password"));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
        try {
            if(resultSet!=null){
                resultSet.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

十、ORM

ORM(Object Relational Mapping)
从数据库查询到的结果集(ResultSet)在进行遍历时,逐行遍历,取出的都是零散的数据。在实际应用开发中,我们都需要将零散的数据进行封装整理。

10.1 实体类(entity):零散数据的载体

一行数据中,多个零散的数据进行整理
通过entity的规则对表中的数据进行对象的封装
表名=类名;列名=属性名;提供各个属性的get,set方法
提供无参构造方法(视情况添加有参构造)

10.1.1 ORM应用
public class T_Jobs {
    private String job_id;
    private String job_title;
    private  String min_salary;
    private String max_salary;

    public T_Jobs() {
    }

    public T_Jobs(String job_id, String job_title, String min_salary, String max_salary) {
        this.job_id = job_id;
        this.job_title = job_title;
        this.min_salary = min_salary;
        this.max_salary = max_salary;
    }

    public String getJob_id() {
        return job_id;
    }

    public void setJob_id(String job_id) {
        this.job_id = job_id;
    }

    public String getJob_title() {
        return job_title;
    }

    public void setJob_title(String job_title) {
        this.job_title = job_title;
    }

    public String getMin_salary() {
        return min_salary;
    }

    public void setMin_salary(String min_salary) {
        this.min_salary = min_salary;
    }

    public String getMax_salary() {
        return max_salary;
    }

    public void setMax_salary(String max_salary) {
        this.max_salary = max_salary;
    }

    @Override
    public String toString() {
        return "T_Jobs{" +
                "job_id='" + job_id + '\'' +
                ", job_title='" + job_title + '\'' +
                ", min_salary='" + min_salary + '\'' +
                ", max_salary='" + max_salary + '\'' +
                '}';
    }
}
public class TestORM {
    public static void main(String[] args) {
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        List<T_Jobs> t_jobsList=new ArrayList<>();

        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement("select * from t_jobs;");
            resultSet=preparedStatement.executeQuery();
            while (resultSet.next()){
                String job_id=resultSet.getString("job_id");
                String job_title=resultSet.getString("job_title");
                String min_salary=resultSet.getString("min_salary");
                String max_salary=resultSet.getString("max_salary");
                T_Jobs t_jobs=new T_Jobs();
                t_jobs.setJob_id(job_id);
                t_jobs.setJob_title(job_title);
                t_jobs.setMin_salary(min_salary);
                t_jobs.setMax_salary(max_salary);
                t_jobsList.add(t_jobs);
            }
            for (T_Jobs t : t_jobsList){
                System.out.println(t);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.closeAll(connection,preparedStatement,resultSet);
        }
    }
}

十一、DAO数据访问对象(Data Access Object)

DAO 实现了业务逻辑与数据库访问相分离
对同一张表的所有操作封装在XxxDAOImpl对象中
根据增删改查的不同功能实现具体的方法(insert、update、delete、select、selectAll)

12.1 创建数据库

创建一张表Person,有以下列:
id:int,主键,自动增长
name:varchar(20) 非空
age:int 非空
bornDate:Date
email:字符串
address:字符串

12.2 封装实体类

创建entity实体类Person,编写属性私有化,构造方法,get/set方法

public class T_Person {
    private int id;
    private String name;
    private int age;
    private Date bornDate;
    private String email;
    private String address;

    public T_Person() {
    }

    public T_Person(String name, int age, Date bornDate, String email, String address) {
        this.name = name;
        this.age = age;
        this.bornDate = bornDate;
        this.email = email;
        this.address = address;
    }

    public T_Person(int id, String name, int age, Date bornDate, String email, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.bornDate = bornDate;
        this.email = email;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBornDate() {
        return bornDate;
    }

    public void setBornDate(Date bornDate) {
        this.bornDate = bornDate;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "T_Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", bornDate=" + bornDate +
                ", email='" + email + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
public class PersonDaoImpl {
    //新增
    public int insert(T_Person person){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        String sql="insert into t_person(name,age,borndate,email,address) values(?,?,?,?,?);";
        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setString(1,person.getName());
            preparedStatement.setInt(2,person.getAge());
            preparedStatement.setDate(3,null);
            preparedStatement.setString(4,person.getEmail());
            preparedStatement.setString(5,person.getAddress());
            int result=preparedStatement.executeUpdate();
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.closeAll(connection,preparedStatement,null);
        }
        return 0;
    };
    //修改
    public int update(T_Person person){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        String sql="update t_person set name=?,age=?,borndate=?,email=?,address=? where id=?;";
        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setString(1,person.getName());
            preparedStatement.setInt(2,person.getAge());
            preparedStatement.setDate(3,null);
            preparedStatement.setString(4,person.getEmail());
            preparedStatement.setString(5,person.getAddress());
            preparedStatement.setInt(6,person.getId());
            int result=preparedStatement.executeUpdate();
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.closeAll(connection,preparedStatement,null);
        }
        return 0;
    };
    //删除
    public int delete(int id){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        String sql="delete from t_person where id=?;";
        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setInt(1,id);
            int result=preparedStatement.executeUpdate();
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.closeAll(connection,preparedStatement,null);
        }
        return 0;
    };
    //查单个
    public T_Person select(int id){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        String sql="select * from t_person where id=?;";
        T_Person person=null;
        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setInt(1,id);
            resultSet=preparedStatement.executeQuery();
            if(resultSet.next()){
                person=new T_Person();
                int pid=resultSet.getInt("id");
                String name=resultSet.getString("name");
                int age=resultSet.getInt("age");
                Date borndate=resultSet.getDate("borndate");
                String email=resultSet.getString("email");
                String address=resultSet.getString("address");
                person.setId(pid);
                person.setName(name);
                person.setAge(age);
                person.setBornDate(borndate);
                person.setEmail(email);
                person.setAddress(address);
            }
            return person;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.closeAll(connection,preparedStatement,resultSet);
        }
        return null;
    };
    //查所有
    public List<T_Person> selectAll(){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        T_Person person=null;
        List<T_Person> personList=new ArrayList<>();
        try {
            connection=DBUtils.getConnection();
            preparedStatement=connection.prepareStatement("select * from t_person;");
            resultSet=preparedStatement.executeQuery();
            while (resultSet.next()){
                int pid=resultSet.getInt("id");
                String name=resultSet.getString("name");
                int age=resultSet.getInt("age");
                Date borndate=resultSet.getDate("borndate");
                String email=resultSet.getString("email");
                String address=resultSet.getString("address");
                person=new T_Person(pid,name,age,borndate,email,address);
                personList.add(person);
            }
            return personList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    };
}
public class TestPerson {
    public static void main(String[] args) {
        PersonDaoImpl personDao=new PersonDaoImpl();
        // 1.新增
//        T_Person person=new T_Person("Gavin",18,null,"Gavin@163.com","北京海淀区");
//        int result=personDao.insert(person);
//        if(result==1){
//            System.out.println("新增成功!");
//        }else{
//            System.out.println("新增失败!");
//        }
        // 2.修改
//        T_Person person=new T_Person(2,"Aaron",20,null,"Aaron@163.com","北京昌平区");
//        int result=personDao.update(person);
//        if(result==1){
//            System.out.println("修改成功!");
//        }else{
//            System.out.println("修改失败!");
//        }
        // 3.删除
//        int result=personDao.delete(2);
//        if(result==1){
//            System.out.println("删除成功!");
//        }else{
//            System.out.println("删除失败!");
//        }
        // 4.查询单个
//        T_Person person=personDao.select(3);
//        System.out.println(person);
        // 5.查询所有
//        List<T_Person> personList=personDao.selectAll();
//        for(T_Person p : personList){
//            System.out.println(p);
//        }
    }
}

十二、Date工具类

现有问题:数据库存储的数据类型为java.sql.Date。而我们java应用层存储日期类型为java.util.Date。当我们用java应用程序插入带有日期的数据到数据库中时,需要进行转换。

12.1 java.util.Date

java语言常规应用层面的日期类型,可以通过字符串创建对应的时间对象。
无法直接通过JDBC插入到数据库

12.2 java.sql.Date

不可以通过字符串创建对应的时间对象,只能通过毫秒值创建对象(1970年至今的毫秒值)
可以直接通过JDBC插入到数据库

12.3 SimpleDateFormat

格式化和解析日期的具体类,允许进行格式化(日期->文本),解析(文本->日期)和规范化。
SimpleDateFormat sdf=new SimpleDateFromat(“yyyy-MM-dd”); //指定日期格式
java.util.Date date=sdf.parse(String dateStr); //将字符串解析成日期类型(java.util.Date)
String dates=sdf.format(data); //将日期格式化成字符串
java.sql.Date sqlDate=new java.sql.Date(date.getTime()); //只支持毫秒值创建对象

public class DateUtils {
    private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
    // 1.字符串转换为util.Date
    public static java.util.Date strToUtil(String str){
        try {
            java.util.Date date=sdf.parse(str);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
    // 2.util.Date转换为sql.Date
    public static java.sql.Date utilToSql(java.util.Date date) {
        return new java.sql.Date(date.getTime());
    }
    // 3.util.Date转换为字符串行
    public static String utilToStr(java.util.Date date){
        return sdf.format(date);
    }
}

十三、Service业务逻辑层

13.1 什么是业务?

代表用户完成的一个业务功能,可以由一个或多个DAO的调用组成。(软件所提供的一个功能都叫业务)

public void register(T_Person person){
	PersonDaoImpl personDao=new PersonDaoImpl();
	//1查询用户是否存在
	T_Person persons=personDao.select(person.getName());
	//2判断用户是否存在,不存在新增,存在提示
	if(persons==null){
		personDao.insert(person);
		System.out.println("注册成功!");
	}else{
		System.out.println("该用户已存在!");
	}
}
13.2 Service开发流程-实现转账功能
public void transMoney(String fromNo,String password,String toNo,double money) {
	Connection connection=null;
	try {
		connection=DBUtils.getConnection();
		connection.setAutoCommit(false);
		AccountDaoImpl accountDao=new AccountDaoImpl();
		Account account=accountDao.select(fromNo);
		//1判断当前卡号是否存在
		if(account==null){
			throw new RuntimeException("当前卡号不存在!");
		}
		//2判断当前卡号密码是否正确
		if(!account.getPassword().equals(password)){
			throw new RuntimeException("当前卡号密码不正确!");
		}
		//3判断当前卡号的余额是否充足
		if(account.getBalance()<money){
			throw new RuntimeException("当前卡号余额不足!");
		}
		Account toAccount=accountDao.select(toNo);
		//4判断对方卡号是否存在
		if(toAccount==null){
			throw new RuntimeException("对方卡号不存在!");
		}
		//5当前卡号扣钱
		account.setBalance(account.getBalance()-money);
		accountDao.update(account);
		//6对方卡号加钱
		toAccount.setBalance(toAccount.getBalance()+money);
		accountDao.update(toAccount);
		System.out.println("转账成功");
		connection.commit();
	} catch (RuntimeException | SQLException e) {
		System.out.println("转账失败:"+e);
		try {
			connection.rollback();
		} catch (SQLException ex) {
			ex.printStackTrace();
		}
	}
}

十四、事务

14.1 service层控制事务
Connection connection=null;
connection=DBUtils.getConnection();
connection.setAutoCommit(false);
connection.commit();
connection.rollback();
14.2 解决方案1:传递Connection

为了解决线程中connection对象不同步问题,可以将connection对象通过service传递给各个DAO方法吗?

14.2.1 传递的问题

如果使用传递Connection,容易造成接口污染(BadSmell)
定义接口是为了更容易实现,而将Connection定义在接口中,会造成污染当前接口。

14.3 解决方案2:ThreadLocal

可以将整个线程中(单线程)中,存储一个共享值。
线程拥有一个类似Map的属性,键值对结构<ThreadLocal对象,值>

14.4 ThreadLocal应用

一个线程共享一个ThreadLocal,在整个流程中任一环节可以存值或取值。

14.5 事务封装工具类
public class DBUtils {
    private static final Properties PROPERTIES=new Properties();//存储配置文件的map
    private static ThreadLocal<Connection> threadLocal=new ThreadLocal<>();
    static {
        InputStream is= com.qf.JDBC2.DBUtils.class.getResourceAsStream("/db.properties");
        try {
            PROPERTIES.load(is);
            Class.forName(PROPERTIES.getProperty("driver"));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void begin(){
        try {
            Connection connection=getConnection();
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void commit(){
        Connection connection=null;
        try {
            connection=getConnection();
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,null,null);
        }
    }
    public static void rollback(){
        Connection connection=null;
        try {
            connection=getConnection();
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,null,null);
        }
    }
    public static Connection getConnection(){
        Connection connection=threadLocal.get();
        try {
            if(connection==null){
                connection= DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("user"),PROPERTIES.getProperty("password"));
                threadLocal.set(connection);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
        try {
            if(resultSet!=null){
                resultSet.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
                threadLocal.remove();//移除connection对象
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

十五、三层架构

15.1 什么是三层?

1.表示层:
命名:XXXView
职责:收集用户的数据和需求、展示数据。
2.业务逻辑层:
命名:XXXServiceImpl
职责:数据加工处理、调用DAO完成业务实现、控制事务。
3.数据访问层:
命名:XXXDaoImpl
职责:向业务层提供数据,将业务层加工后的数据同步到数据库。

15.2 三层架构项目搭建(按开发步骤)

utils:存放工具类(DBUtils)
entity:存放实体类(Person)
dao:存放DAO接口(PersonDao)
impl:存放DAO接口实现类(PersonDaoImpl)
service:存放service接口(PersonService)
impl:存放service接口实现类(PersonServiceImpl)
View:存放程序启动类(main)
注意:程序设计时,考虑易修改、易扩展,为service层和DAO层设计接口,便于未来更换实现类

十六、DaoUtils

在DAO层中,对数据库表的增删改查操作存在代码冗余,可对其进行抽取封装DaoUtil工具类实现复用。

public class DaoUtils<T> {
    public int commonsUpdate(String sql,Object... args){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        connection=DButils.getConnection();
        try {
            preparedStatement=connection.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            int result=preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButils.closeAll(null,null,null);
        }
        return 0;
    }
    public List<T> commonSelect(String sql, RowMapper<T> rowMapper, Object... args){
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        List<T> list=new ArrayList<>();

        connection=DButils.getConnection();
        try {
            preparedStatement=connection.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            resultSet=preparedStatement.executeQuery();
            while (resultSet.next()){
                T t=rowMapper.getRow(resultSet);//回调——>调用者提供的一个封装方法ORM
                list.add(t);
            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }
}

十七、Druid连接

在程序初始化时,预先创建指定数量的数据库连接对象存储在池中。当需要连接数据库时,从连接池中取出现有连接;使用完毕后,也不会进行关闭,而是放回池中,实现复用,节省资源。

17.1 Druid连接池使用步骤

创建database.properties配置文件。
引入druid-1.1.5.jar文件

17.1.1 database.properties配置文件

//连接设置
driverClassName=com.jdbc.Driver
url=jdbc:mysql://localhost:3306/school
username=root
password=123456
//初始化连接
initialSize=10
//最大连接数
maxActive=50
//最小空闲连接
minIdle=5
//超时等待时间以毫秒为单位 60000毫秒/1000等于60秒
maxWait=5000

17.1.2连接池工具类
public class DBUtils {
    //声明连接池对象
    private static DruidDataSource ds;
    static {
        Properties properties=new Properties();
        InputStream is=DBUtils.class.getResourceAsStream("/database.properties");
        try {
            properties.load(is);
            ds=(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection(){
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

十八、Apache的DbUtils使用

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

18.1 DbUtils简介

DbUtils是Java编程中数据库操作实用小工具,小巧、简单、实用
对于数据表的查询操作,可以把结果转换为List、Array、Set等集合。便于操作
对于数据表的DML操作,也变得很简单(只需要写SQL语句)

18.1.1 DbUtils主要包含

ResultSetHandler接口:转换类型接口
BeanHandler类:实现类,把一条记录转换成对象。
BeanListHandler类:实现类,把多条记录转换成List集合。
ScalarHandler类:实现类,适合获取一行一列的数据。
QueryRunner:执行sql语句的类
增、删、改:update()
查询:query()

18.2 DbUtils的使用步骤

导入jar包
mysql连接驱动jar包
druid-1.1.5.jar
database.properties
commons-dbutils-1.6.jar

18.2.1 代码实现

DBUtils工具类

public class DBUtils {
    //声明连接池对象
    private static DruidDataSource ds;
    static {
        Properties properties=new Properties();
        InputStream is=DBUtils.class.getResourceAsStream("/database.properties");
        try {
            properties.load(is);
            ds=(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection(){
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static DataSource getDateSource(){
        return ds;
    }
}
public class TestPerson {
    private QueryRunner queryRunner=new QueryRunner(DBUtils.getDateSource());
    public int insert(Object person){
        Object[] params={person.getUserId(),person.getName(),person.getAge()};
        try {
            int result=queryRunner.update("insert into person(userid,name,age) values(?,?,?)",params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
	public int select(int id){
        try {
            Person person=queryRunner.query("select * from user where userId=?",new BeanHandler<Person>(Person.class),id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
	public int selectAll(){
	    try {
	        Person person=queryRunner.query("select * from user",new BeanListHandler<Person>(Person.class));
	    } catch (SQLException e) {
	        e.printStackTrace();
	    }
	}
	public long selectUserNums(){
	    try {
	        return queryRunner.query("select count(*) from user;",new ScalarHandler<>());
	    } catch (SQLException e) {
	        e.printStackTrace();
	    }
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风紧不扯呼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值