数据库连接JDBC

概述

✅概念
JDBC(JavaDataBaseConnectivityjava数据库连接)是⼀种⽤于执⾏SQL语句的JavaAPI,可以为多种关系型数据库提供
统⼀访问,它是由⼀组⽤Java语⾔编写的类和接⼝组成的。
本质
其实就是java官⽅提供的⼀套规范(接⼝)。⽤于帮助开发⼈员快速实现不同关系型数据库的连接!

功能详解

public class JDBCQuick {
    public static void main(String[] args) throws Exception {
        //1.注册驱动(可省略)
 
//        Class.forName("com.mysql.cj.jdbc.Driver");
 //        DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
        //2.获取连接对象
 
        String url = "jdbc:mysql://localhost:3306/itcast";
        String user = "root";
        String password = "20050606a";
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.获取执⾏SQL语句的对象
 
        Statement statement = connection.createStatement();
        System.out.println("请输⼊员⼯的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name1 = scanner.nextLine();
        //4.编写SQL语句,并执⾏,接受返回的结果集
 
        String sql = "select * from employee where name='"+name1+"'";
        ResultSet resultSet = statement.executeQuery(sql);
        //5.处理结果遍历resultSet结果集
 
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String workno= resultSet.getString("workno");
            String name = resultSet.getString("name");
            String gender = resultSet.getString("gender");
            int age = resultSet.getInt("age");
            String idcard = resultSet.getString("idcard");
            Date entrydate = resultSet.getDate("entrydate");
            String workaddress = resultSet.getString("workaddress");
            
System.out.println(id+"\t"+workno+"\t"+name+"\t"+gender+"\t"+age+"\t"+idcard+"\t"+entrydate+"\t"+workaddress);
        }
        //6.释放资源(先开后关)
 
        resultSet.close();
        statement.close();
        connection.close();
    }
 }
public class JDBCPrepareStatement {
    public static void main(String[] args) throws Exception {
        //1.
注册驱动
(
可省略)
 
//        Class.forName("com.mysql.cj.jdbc.Driver");
 //        DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
        //2.获取连接对象
 
        String url = "jdbc:mysql://localhost:3306/itcast";
        String user = "root";
        String password = "20050606a";
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.获取执⾏SQL语句的对象,防⽌SQL注⼊
 
        PreparedStatement preparedStatement = connection.prepareStatement("select * from employee where name=?");
        System.out.println("请输⼊员⼯的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name1 = scanner.nextLine();
        //4.为?占位符赋值,并执⾏SQL语句,接受返回的结果集
 
        preparedStatement.setString(1, name1);
        ResultSet resultSet = preparedStatement.executeQuery();
        //5.处理结果遍历resultSet结果集
 
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String workno= resultSet.getString("workno");
            String name = resultSet.getString("name");
            String gender = resultSet.getString("gender");
            int age = resultSet.getInt("age");
            String idcard = resultSet.getString("idcard");
            Date entrydate = resultSet.getDate("entrydate");
            String workaddress = resultSet.getString("workaddress");
            
System.out.println(id+"\t"+workno+"\t"+name+"\t"+gender+"\t"+age+"\t"+idcard+"\t"+entrydate+"\t"+workaddress);
        }
        //6.释放资源(先开后关)
 
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
 }

DriverManager驱动管理对象

✅(1)注册驱动:(mysql5以后可直接省略驱动)
1.注册给定的驱动程序:staticvoidregisterDriver(Driverdriver);
2.写代码使⽤:Class.forName(“com.mysql.jdbc.Driver”);
3.在com.mysql.jdbc.Driver类中存在静态代码块
(2)获取数据库连接:
1.获取数据库连接对象:staticConnectiongetConnection(Stringurl,Stringuser,Stringpassword)
2.返回值:Connection数据库连接对象
3.参数
url:指定连接的路径。语法:jdbc:mysql://ip地址(域名):端⼝号/数据库名称
user:⽤⼾名
password:密码

Connection数据库连接对象

✅1.获取执⾏者对象:
获取普通执⾏者对象:StatementcreateStatement0;
获取预编译执⾏者对象:PreparedStatementprepareStatement(Stringsql);
2.管理事务
开启事务:setAutoCommit(booleanautoCommit);参数为false,则开启事务
提交事务:commit();
回滚事务:rollback();
3.释放资源
⽴即将数据库连接对象释放:voidclose();

Statement执⾏sql语句的对象

✅(1)执⾏DML语句:intexecuteUpdate(Stringsql);
返回值int:返回影响的⾏数。
参数sql:可以执⾏insert、update、delete语句。
(2) 执⾏DQL语句:ResultSetexecuteQuery(Stringsql);
返回值ResultSet:封装查询的结果。
参数sql:可以执⾏select语句。
(3)释放资源
⽴即将数据库连接对象释放:voidclose();

ResultSet结果集对象

✅1.判断结果集中是否还有数据:booleannext();
有数据返回true,并将索引向下移动⼀⾏。没有数据返回false。
2.获取结果集中的数据:XXXgetXxx(“列名”);XXX代表数据类型(要获取某列数据,这⼀列的数据类型)。
例如:StringgetString(“name”);
int getInt(" age");
3.释放资源
⽴即将结果集对象释放:voidclose();

ORM

ORM是⼀种思想,ORM(全称为:ObjectRelativeMapping)对象-关系映射

关系数据库是企业级应⽤环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实
体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,⽽在数据库中,关系数据
⽆法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统⼀般以中间件的形式存在,主要实现程序对象到关
系数据库数据的映射。

ORM模型的简单性简化了数据库查询过程。使⽤ORM查询⼯具,⽤⼾可以访问期望数据,⽽不必理解数据库的底层结构。

  • 在使⽤JDBC操作数据库时,我们会发现数据都是零散的,明明在数据库中是⼀⾏完整的数据,到了Java中变成了⼀
    个⼀个的变量,不利于维护和管理。⽽我们Java是⾯向对象的,⼀个表对应的是⼀个类,⼀⾏数据就对应的是Java
    中的⼀个对象,⼀个列对应的是对象的属性,所以我们要把数据存储在⼀个载体⾥,这个载体就是实体类!
  • ORM(ObjectRelationalMapping)思想,对象到关系数据库的映射,作⽤是在编程中,把⾯向对象的概念
    跟数据库中表的概念对应起来,以⾯向对象的⻆度操作数据库中的数据,即⼀张表对应⼀个类,⼀⾏数据对应⼀个对 象,⼀个列对应⼀个属性!
  • 当下JDBC中这种过程我们称其为⼿动ORM。后续我们也会学习ORM框架,⽐如MyBatis、JPA等。
    在这里插入图片描述
    在这里插入图片描述
public class Student {
 private Integer stuID;//stu_id
 private String stuName;//sut_name
 private Integer stuAge;//stu_age
 public Student() {
 }
 public Student(String stuName, Integer stuID, Integer stuAge) {
 this.stuName = stuName;
 this.stuID = stuID;
 this.stuAge = stuAge;
 }
 @Override
 public String toString() {
 return "Student{" +
 "stuID=" + stuID +
 ", stuName='" + stuName + '\'' +
 ", stuAge=" + stuAge +
 '}';
 }
  public Integer getStuID() {
        return stuID;
    }
    public void setStuID(Integer stuID) {
        this.stuID = stuID;
    }
    public String getStuName() {
        return stuName;
    }
    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
    public Integer getStuAge() {
        return stuAge;
    }
    public void setStuAge(Integer stuAge) {
        this.stuAge = stuAge;
    }
 }

 public class JDBCAdvanced {
    @Test
    public void testORM() throws SQLException {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");
        PreparedStatement preparedStatement = connection.prepareStatement("select * from t_stu where stu_id=?");
        preparedStatement.setInt(1, 1);
        ResultSet resultSet = preparedStatement.executeQuery();
        Student student = null;
        if(resultSet.next()) {
            int stuId = resultSet.getInt("stu_id");
            String stuName = resultSet.getString("stu_name");
            int stuAge = resultSet.getInt("stu_age");
            //为对象的属性赋值
 
            student=new Student();
            student.setStuID(stuId);
            student.setStuName(stuName);
            student.setStuAge(stuAge);
        }
        System.out.println(student);
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
    @Test
    public void testORMList() throws Exception {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");
        PreparedStatement preparedStatement = connection.prepareStatement("select * from t_stu ");
        ResultSet resultSet = preparedStatement.executeQuery();
        Student student = null;
        List<Student> list = new ArrayList<Student>();
        while(resultSet.next()) {
            student = new Student();
            int stuId = resultSet.getInt("stu_id")
     String stuName = resultSet.getString("stu_name");
            int stuAge = resultSet.getInt("stu_age");
            //为对象的属性赋值
 
            student=new Student();
            student.setStuID(stuId);
            student.setStuName(stuName);
            student.setStuAge(stuAge);
            list.add(student);
        }
        for(Student stu:list){
            System.out.println(stu);
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
 }        

主键回显

✅-在数据中,执⾏新增操作时,主键列为⾃动增⻓,可以在表中直观的看到,但是在Java程序中,我们执⾏完新增后,只
能得到受影响⾏数,⽆法得知当前新增数据的主键值。在Java程序中获取数据库中插⼊新数据后的主键值,并赋值给Java
对象,此操作为主键回显。

public void testReturnPK() throws SQLException {
    //获取连接
 
    Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");
    //预编译SQL语句,告知prapareStatement,返回新增数据的主键列的值
 
    String sql = "insert t_stu (stu_name,stu_age) values(?,?);";
    PreparedStatement preparedStatement = connection.prepareStatement(sql, 
Statement.RETURN_GENERATED_KEYS);
    //创建对象,将对象的属性值,填充到?占位符上(ORM)
 
    Student student = new Student("Bob", null, 21);
    preparedStatement.setString(1, student.getStuName());
    preparedStatement.setInt(2, student.getStuAge());
    //执⾏SQL语句,并获取返回的结果
 
    int i = preparedStatement.executeUpdate();
    //处理结果
 
    ResultSet resultSet = null;
    if (i > 0) {
        System.out.println("成功");
        //获取新增的主键列,回显到Student对象的stuId属性上
 
        //返回主键的值,是⼀个单⾏单列的值储存再resultSet⾥
 
        resultSet = preparedStatement.getGeneratedKeys();
        if (resultSet.next()) {
            int stuId = resultSet.getInt(1);
            student.setStuID(stuId);
        }
        System.out.println(student);
    } else {
        System.out.println("失败");
    }
    //关闭资
 
    if (resultSet != null) {
        resultSet.close();
    }
    preparedStatement.close();
       connection.close();
 }

批量操作

插⼊多条数据时,⼀条⼀条发送给数据库执⾏,效率低下!
通过批量操作,可以提升多次操作效率!
注意:1、必须在连接数据库的URL后⾯追加?rewriteBatchedStatements=true,允许批量操作
2、新增SQL必须⽤values。且语句最后不要追加;结束
3、调⽤addBatch()⽅法,将SQL语句进⾏批量添加操作
4、统⼀执⾏批量操作,调⽤executeBatch()

 @Test
 public void testBatch() throws SQLException {
    //批量操作
 
    Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast?
 rewriteBatchedStatements=true", "root", "20050606a");
    //预编译SQL语句,告知prapareStatement,返回新增数据的主键列的值
 
    //必须是values,不能加分号
 
    String sql = "insert t_stu (stu_name,stu_age) values(?,?)";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    long start = System.currentTimeMillis();
    for(int i=1;i<=10000;i++){
        preparedStatement.setString(1, "name"+i);
        preparedStatement.setInt(2, 1+i);
        //使⽤addBatch() 
        preparedStatement.addBatch();
    }
    //执⾏批量操作
 
    preparedStatement.executeBatch();
    long end = System.currentTimeMillis();
    System.out.println("消耗的时间"+(end-start));
    preparedStatement.close();
    connection.close();
 }

SQL注⼊

原理

  • sql注⼊攻击:就是利⽤sql语句的漏洞来对系统进⾏攻击
  • 按照正常道理来说,我们在密码处输⼊的所有内容,都应该认为是密码的组成
  • 但是现在Statement对象在执⾏sql语句时,将⼀部分内容当做查询条件来执⾏了

PreparedStatement的介绍
✅预编译sql语句的执⾏者对象。在执⾏sql语句之前,将sql语句进⾏提前编译
明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数
参数使⽤?作为占位符
为参数赋值的⽅法:setXxx(参数1,参数2);
参数1:?的位置编号(编号从1开始)
参数2:?的实际参数
执⾏sql语句的⽅法
执⾏insert、update、delete语句:intexecuteUpdate();
执⾏select语句:ResultSetexecuteQuery();

 /*
         
使⽤
PreparedStatement
的登录⽅法,解决注⼊攻击
 
*/
 @Override
 public User findByLoginNameAndPassword(String loginName, String password) {
    //定义必要信息
 
    Connection conn = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    User user = null;
    try {
        //1.获取连接
 
        conn = JDBCUtils.getConnection();
        //2.创建操作SQL对象
 
        String sql = "SELECT * FROM user WHERE loginname=? AND password=?";
        pstm = conn.prepareStatement(sql);
        //3.设置参数
 
        pstm.setString(1,loginName);//设置第⼀个?参数
 
        pstm.setString(2,password);//设置第⼆个?参数
 
        System.out.println(sql);
        //4.执⾏sql语句,获取结果集
 
        rs = pstm.executeQuery();
        //5.获取结果集
 
        if (rs.next()) {
            //6.封装
 
            user = new User();
            user.setUid(rs.getString("uid"));
            user.setUcode(rs.getString("ucode"));
            user.setUsername(rs.getString("username"));
            user.setPassword(rs.getString("password"));
            user.setGender(rs.getString("gender"));
            user.setDutydate(rs.getDate("dutydate"));
            user.setBirthday(rs.getDate("birthday"));
            user.setLoginname(rs.getString("loginname"));
        }
        //7.返回
 
        return user;
    }catch (Exception e){
        throw new RuntimeException(e);
    }finally {
        JDBCUtils.close(conn,pstm,rs);
    }
    }

连接池

概念
数据库连接背景
数据库连接是⼀种关键的、有限的、昂贵的资源,这⼀点在多⽤⼾的⽹⻚应⽤程序中体现得尤为突出
对数据库连接的管理能显著影响到整个应⽤程序的伸缩性和健壮性,影响到程序的性能指标
数据库连接池正是针对这个问题提出来的
数据库连接池
数据库连接池负责分配、管理和释放数据库连接
它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个
这项技术能明显提⾼对数据库操作的性能
数据库连接池原理
之前的程序:来⼀个访问就会创建⼀个连接,使⽤完了关闭连接。频繁的创建连接和关闭连接是⾮常耗时的。
优化后的程序:提前准备⼀些数据库连接,使⽤的时候从池中获取,⽤完后重新归还给池中。

连接池就是数据库连接对象的缓冲区,通过配置,由连接池负责创建连接、管理连接、释放连接等操作。
预先创建数据库连接放⼊连接池,⽤⼾在请求时,通过池直接获取连接,使⽤完毕后,将连接放回池中,避免了频繁的
创建和销毁,同时解决了创建的效率。
当池中⽆连接可⽤,且未达到上限时,连接池会新建连接。
池中连接达到上限,⽤⼾请求会等待,可以设置超时时间。

常⻅连接池

JDBC的数据库连接池使⽤javax.sql.DataSource接⼝进⾏规范,所有的第三⽅连接池都实现此接⼝,⾃⾏添加具体实
现!也就是说,所有连接池获取连接的和回收连接⽅法都⼀样,不同的只有性能和扩展功能!

  • DBCP是Apache提供的数据库连接池,速度相对C3P0较快,但⾃⾝存在⼀些BUG。
  • C3P0是⼀个开源组织提供的⼀个数据库连接池,速度相对较慢,稳定性还可以。
  • Proxool 是sourceforge下的⼀个开源项⽬数据库连接池,有监控连接池状态的功能,稳定性较c3p0差⼀点
  • Druid 是阿⾥提供的数据库连接池,是集DBCP、C3P0、Proxool优点于⼀⾝的数据库连接池,性能、扩展性、易⽤
    性都更好,功能丰富。
  • Hikari(ひかり[shigali])取⾃⽇语,是光的意思,是SpringBoot2.x之后内置的⼀款连接池,基于BoneCP(已经
    放弃维护,推荐该连接池)做了不少的改进和优化,⼝号是快速、简单、可靠。

Druid

硬编码

 public void testDruidHardTest() throws SQLException {
 /* 硬编码:将连接池的配置信息和Java代码耦合在⼀起。
 
1、创建HikariDataSource连接池对象
 
2、设置连接池的配置信息【必须|⾮必须】
 
3、通过连接池获取连接对象
 
4、回收连接
*/ 
DruidDataSource druidDataSource = new DruidDataSource();
 //必须设置的配置
 
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
 druidDataSource.setUrl("jdbc:mysql:///itcast");
 druidDataSource.setUsername("root");
 druidDataSource.setPassword("20050606a");
 //⾮必须设置的配置
 
//基于connection的增删改查
 
druidDataSource.setInitialSize(10);
 druidDataSource.setMaxActive(20);
 DruidPooledConnection connection = druidDataSource.getConnection();
 System.out.println(connection);
 connection.close();
 }

软编码
✅db.properties

driverClassName=com.mysql.cj.jdbc.Driver
 url=jdbc:mysql:///itcast
 username=root
 password=20050606a
 initialSize=10
 maxActive=20
 public void test() throws Exception {
 //1.创建Properties集合,⽤于存储外部配置⽂件的key和value值。
 
Properties properties = new Properties();
 //2.读取外部配置⽂件,获取输⼊流,加载到Properties集合⾥。
 
InputStream inputStream = DruidTest.class.getClassLoader().getResourceAsStream("db.properties");
 properties.load(inputStream);
 //3.基于Properties集合构建DruidDataSource连接池
 
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
 //4.通过连接池获取连接对象
 
Connection connection = dataSource.getConnection();
 System.out.println(connection);
 //5.开发CRUD 
//6.回收连接
 
connection.close();
 }

Hikari

硬编码

 @Test
 public void testHardTestHikari() throws SQLException {
 /* 硬编码:将连接池的配置信息和Java代码耦合在⼀起。
 
1、创建HikariDataSource连接池对象
 
2、设置连接池的配置信息【必须|⾮必须】
 
3、通过连接池获取连接对象
 
4、回收连接
*/ 
//1.创建HikariDataSource连接池对象
 
HikariDataSource hikariDataSource = new HikariDataSource();
 //2.设置连接池的配置信息【必须 | ⾮必须】
 
//2.1必须设置的配置
 
hikariDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
 hikariDataSource.setJdbcUrl("jdbc:mysql:///itcast");
 hikariDataSource.setUsername("root");
 hikariDataSource.setPassword("20050606a");
 //2.2 ⾮必须设置的配置
 
hikariDataSource.setMinimumIdle(10);
 hikariDataSource.setMaximumPoolSize(20);
 //3.通过连接池获取连接对象
 
Connection connection = hikariDataSource.getConnection();
 System.out.println(connection);
 //回收连接
 
connection.close();
 }

软编码

 @Test
 public void testResourcesHikari() throws Exception {
 //1.创建Properties集合,⽤于存储外部配置⽂件的key和value值。
 
Properties properties = new Properties();
 //2.读取外部配置⽂件,获取输⼊流,加载到Properties集合⾥。
 
InputStream inputStream = HikariTest.class.getClassLoader().getResourceAsStream("hikari.properties");
 properties.load(inputStream);
 // 3.创建Hikari连接池配置对象,将Properties集合传进去
 
HikariConfig hikariConfig = new HikariConfig(properties);
 // 4. 基于Hikari配置对象,构建连接池
 
HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
// 5. 
获取连接
 
    Connection connection = hikariDataSource.getConnection();
    System.out.println("connection = " + connection);
    //6.
回收连接
 
    connection.close();
 }

JDBC优化及⼯具类的封装

JDBC⼯具类封装1.0

package senior.util;
 import com.alibaba.druid.pool.DruidDataSourceFactory;
 import javax.sql.DataSource;
 import java.io.IOException;
 import java.io.InputStream;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Properties;
 public class JDBCUtil {
    //创建连接池引⽤
 
    private static DataSource dataSource;
    static {
        try{
        Properties prop = new Properties();
        InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
            prop.load(inputStream);
            dataSource= DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //对外提供在连接池中获取连接的⽅法
 
    public  static Connection getConnection(){
        try{
            return dataSource.getConnection();
        }catch (SQLException e){
            throw new RuntimeException(e);
        }
    }
    //对外提供回收连接的⽅法
 
    public static void release(Connection connection){
        try {
            connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
 }

JDBC⼯具类封装2.0

package senior.util;
 import com.alibaba.druid.pool.DruidDataSourceFactory;
 import javax.sql.DataSource;
 import java.io.InputStream;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Properties;
 public class JDBCUtilV2 {
    //维护⼀个连接池对象,维护了⼀个线程绑定变量的ThreadLocal对象
 
    private static DataSource dataSource;
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    static {
        try{
        Properties prop = new Properties();
        InputStream inputStream = JDBCUtilV2.class.getClassLoader().getResourceAsStream("db.properties");
            prop.load(inputStream);
            dataSource= DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //对外提供在ThreadLocal中获取连接对象的⽅法
 
    public  static Connection getConnection(){
        try{
            //在ThreadLocal中获取connection 
            Connection connection= threadLocal.get();
            if(connection==null){
                connection= dataSource.getConnection();
                threadLocal.set(connection);
            }
            return connection;
        }catch (SQLException e){
            throw new RuntimeException(e);
        }
    }
    //对外提供回收连接的⽅法,回收过程中,将回收的连接从ThreadLocal中移除!
 
    public static void release(){
        try {
            Connection connection = threadLocal.get();
            if(connection!=null){
                threadLocal.remove();
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
 

Dao封装及DaoBase⼯具类

DaseDAO

 package senior.dao;
 import senior.util.JDBCUtil;
 import senior.util.JDBCUtilV2;
 import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.util.ArrayList;
 import java.util.List;
 public class BaseDAO {
    //通⽤的增删改⽅法
 
    public int executeUpdate(String sql,Object...params) throws Exception {
        Connection connection= JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null&&params.length>0){
            for(int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        int updateCount = preparedStatement.executeUpdate();
        preparedStatement.close();
        JDBCUtilV2.release();
        return updateCount;
    }
    //通⽤的查询⽅法
 
    public <T> List<T> executeQuery(Class<T> clazz,String sql,Object...params) throws Exception {
        Connection connection= JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null&&params.length>0){
            for(int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        //获取结果集中的元数据对象
 
        //包含了:列的数量、每个列的名称
 
        ResultSetMetaData metaData=resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        List<T> list=new ArrayList<>();
        while(resultSet.next()){
            //循环⼀次通过反射创建⼀个对象
 
            T t = clazz.newInstance();
            for(int i=1;i<=columnCount;i++){
                Object value = resultSet.getObject(i);
                //获取列的名字=对象的属性
 
                String filedName = metaData.getColumnLabel(i);
                //通过对象和filedName获取要封装的属性
 
                Field field = clazz.getDeclaredField(filedName);
                field.setAccessible(true);
                field.set(t,value);
            }
            list.add(t);
        }
        resultSet.close();
        preparedStatement.close();
        JDBCUtilV2.release();
        return list;
    }
    //通⽤的查询单个结果的⽅法
 
    public <T> T executeQueryBean(Class<T> clazz,String sql,Object...params) throws Exception {
        List<T> list=this.executeQuery(clazz,sql,params);
        if(!list.isEmpty()){
            return null;
        }
        return list.get(0);
    }
 }

StudentDao

package senior.dao;
 import senior.pojo.Student;
 import java.util.List;
 public interface StudentDao {
    List<Student> selectAllStudents();
    Student selectStudentById(int id);
    int insertStudent(Student student);
    int updateStudent(Student student);
    int deleteStudent(int id);
 }

StudentDaoImpl

package senior.dao;
 import senior.pojo.Student;
 import java.util.List;
 public class StudentDaoImpl extends BaseDAO implements StudentDao{
    @Override
    public List<Student> selectAllStudents() {
        String sql="SELECT stu_id stuID ,stu_name stuName,stu_age stuAge from itcast.t_stu";
        try {
            return executeQuery(Student.class,sql,null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public Student selectStudentById(int id) {
        String sql="SELECT stu_id stuID ,stu_name stuName,stu_age stuAge from itcast.t_stu where stu_id=?";
        try {
            return executeQueryBean(Student.class,sql,id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public int insertStudent(Student student) {
        String sql="INSERT INTO  itcast.t_stu (stu_name, stu_age) values (?,?)";
        try {
          return executeUpdate(sql,student.getStuName(),student.getStuAge());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public int updateStudent(Student student) {
        String sql="Update itcast.t_stu SET stu_name =? where stu_age=?";
        try {
            return executeUpdate(sql,student.getStuName(),student.getStuAge());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public int deleteStudent(int id) {
        String sql="DELETE FROM itcast.t_stu WHERE stu_id=?";
        try {
            return executeUpdate(sql,id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
 }

事务

Show VARIABLES LIKE 'autocommit';
 SET autocommit =false;
 COMMIT ;
 ROLLBACK ;
 UPDATE t_bank SET money=money-100 WHERE id=1;
 UPDATE t_bank SET money=money+100 WHERE id=2;
 CREATE TABLE t_bank(
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '账号主键',
    account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
    money INT UNSIGNED COMMENT '⾦额'
 )COMMENT '银⾏账⼾';
 INSERT INTO t_bank(account, money) VALUES ('张三',1000);
 INSERT INTO t_bank(account, money) VALUES ('李四',1000);
 package senior.dao;
 import senior.util.JDBCUtil;
 import senior.util.JDBCUtilV2;
 import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.util.ArrayList;
 import java.util.List;
 public class BaseDAO {
    //通⽤的增删改⽅法
 
    public int executeUpdate(String sql,Object...params) throws Exception {
        Connection connection= JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null&&params.length>0){
            for(int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        int updateCount = preparedStatement.executeUpdate();
        preparedStatement.close();
        if(connection.getAutoCommit()){
            JDBCUtilV2.release();
        }
        return updateCount;
    }
    //通⽤的查询⽅法
 
    public <T> List<T> executeQuery(Class<T> clazz,String sql,Object...params) throws Exception {
        Connection connection= JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null&&params.length>0){
            for(int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        //获取结果集中的元数据对象
 
        //包含了:列的数量、每个列的名称
 
        ResultSetMetaData metaData=resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        List<T> list=new ArrayList<>();
        while(resultSet.next()){
            //循环⼀次通过反射创建⼀个对象
 
            T t = clazz.newInstance();
            for(int i=1;i<=columnCount;i++){
                Object value = resultSet.getObject(i);
                //获取列的名字=对象的属性
 
                String filedName = metaData.getColumnLabel(i);
                //通过对象和filedName获取要封装的属性
 
                Field field = clazz.getDeclaredField(filedName);
                field.setAccessible(true);
                field.set(t,value);
            }
            list.add(t);
        }
        resultSet.close();
        preparedStatement.close();
        if(connection.getAutoCommit()){
            JDBCUtilV2.release();
        }
        return list;
    }
    //通⽤的查询单个结果的⽅法
 
    public <T> T executeQueryBean(Class<T> clazz,String sql,Object...params) throws Exception {
        List<T> list=this.executeQuery(clazz,sql,params);
        if(!list.isEmpty()){
            return null;
        }
        return list.get(0);
    }
 }
package senior.util;
 import com.alibaba.druid.pool.DruidDataSourceFactory;
 import javax.sql.DataSource;
 import java.io.InputStream;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Properties;
 public class JDBCUtilV2 {
    //维护⼀个连接池对象,维护了⼀个线程绑定变量的ThreadLocal对象
 
    private static DataSource dataSource;
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    static {
        try{
        Properties prop = new Properties();
        InputStream inputStream = JDBCUtilV2.class.getClassLoader().getResourceAsStream("db.properties");
            prop.load(inputStream);
            dataSource= DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //对外提供在ThreadLocal中获取连接对象的⽅法
 
    public  static Connection getConnection(){
        try{
            //在ThreadLocal中获取connection 
            Connection connection= threadLocal.get();
            if(connection==null){
                connection= dataSource.getConnection();
                threadLocal.set(connection);
            }
            return connection;
        }catch (SQLException e){
            throw new RuntimeException(e);
        }
    }
    //对外提供回收连接的⽅法,回收过程中,将回收的连接从ThreadLocal中移除!
 
    public static void release(){
        try {
            Connection connection = threadLocal.get();
            if(connection!=null){
                threadLocal.remove();
                connection.setAutoCommit(true);
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值