JDBC进阶篇

一、JDBC扩展

1.1.实体类和ORM

(1)在使用JDBC操作数据库时,我们会发现数据都是零散的,明明在数据库中是一行完整的数据,到了Java中变成了一个一个的变量,不利于维护和管理。而我们Java是面向对象的,一个表对应的是一个类,一行数据就对应的是Java中的一个对象,一个列对应的是对象的属性,所以我们要把数据存储在一个载体里,这个载体就是实体类

(2)ORM(Object Relational Mapping)思想,对象到关系数据库的映射,作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来,以面向对象的角度操作数据库中的数据,即一张表对应一个类,一行数据对应一个对象,一个列对应一个属性;

(3)当下JDBC中这种过程我们称其为手动ORM。后续我们也会学习ORM框架,比如MyBatis、JPA等

//类名就是数据表t_后面的单词全写
public class Employee{
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;
    //空参和全参的构造方法
    public Employee(){};
    public Employee(Integer empId,String empName,Double empSalary,Integer empAge)    {
    this.empId = empId;    
    this.empName = empName;
    this.empSalary = empSalary;
    this.empAge = empAge;
    }
    //每个属性的get和set方法以及toString()方法
}
public class JDBCAdvanced{
    

    public void testORM(){
        Connection connection     DriverManager.getConnection("jdbc:mysql:///atguigu","root","abc123");
        PreparedStatement preparedStatement = connection.prepareStatement("SELECT emp_id,emp_name,emp_salary FROM t_emp WHERE emp_id = ?");
        prepareStatement.setInt(1,5);
        ResultSet resultSet = preparedStatement.executeQuery();
        Employee employee = null;
        while(resultSet.next()){
            int emp_id = resultSet.getInt("emp_id ");
            String emp_name = resultSet.getString("emp_name");
            double emp_salary = resultSet.getDouble("emp_salary");
            employee = new Employee(emp_id,emp_name,emp_salary);
            System.out.println(employee);
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
        }
    }
    public void testORMList(){
        Connection connection     DriverManager.getConnection("jdbc:mysql:///atguigu","root","abc123");
        PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM t_emp");
        prepareStatement.setInt(1,5);
        ResultSet resultSet = preparedStatement.executeQuery();
        Employee employee = null;
        List<Employee> el = new ArrayList<>();
        while(resultSet.next()){
            int emp_id = resultSet.getInt("emp_id ");
            String emp_name = resultSet.getString("emp_name");
            double emp_salary = resultSet.getDouble("emp_salary");
            employee = new Employee(emp_id,emp_name,emp_salary);
            el.add(employee);
            System.out.println(employee);
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
        }
    }

1.2.主键回显

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

//类名就是数据表t_后面的单词全写
public class Employee{
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;
    //空参和全参的构造方法
    public Employee(){};
    public Employee(Integer empId,String empName,Double empSalary,Integer empAge)    {
    this.empId = empId;    
    this.empName = empName;
    this.empSalary = empSalary;
    this.empAge = empAge;
    }
    //每个属性的get和set方法以及toString()方法
}
public class JDBCAdvanced{
    public void testReturnPK(){
        Connection connection     DriverManager.getConnection("jdbc:mysql:///atguigu","root","abc123");
        PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO t_emp(emp_name,emp_salary,emp_age) VALUES (?,?,?)",Statement.RETURN_GENERATED_KEYS);
        ResultSet resultSet = preparedStatement.executeQuery();
        Employee employee = new Employee(null,"Jack",29);
        preparedStatement.setString(1,employee.getEmpName());
        preparedStatement.setDouble(2,employee.getEmpSalary());
        preparedStatement.setInt(3, employee.getEmpAge());
        int result =preparedStatement.executeUpdate();
        if(result>0){
            ResultSet resultSet = preparedStatement.getGeneratedKeys();
            while(resultSet.next()){
                int emp_id = resultSet.getInt(1);
                employee.setEmpId(emp_id);
            }
            resultSet.close();
            }
        }
        preparedStatement.close();
        connection.close();
    }
}

1.3.批量操作

(1)必须在连接数据库的URL后面追加?rewriteBatchedStatements=true,允许批量操作

(2)新增SQL必须用values,且语句最后不要追加;结束

(3)调用addBatch()方法,将SQL语句进行批量添加操作

(4)统一执行批量操作,调用executeBatch()

//类名就是数据表t_后面的单词全写
public class Employee{
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;
    //空参和全参的构造方法
    public Employee(){};
    public Employee(Integer empId,String empName,Double empSalary,Integer empAge)    {
    this.empId = empId;    
    this.empName = empName;
    this.empSalary = empSalary;
    this.empAge = empAge;
    }
    //每个属性的get和set方法以及toString()方法
}
public class JDBCAdvanced{
   public void testMoreInsert(){
        Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu?rewriteBatchedStatements=true","root","atguigu");
        String sql = "insert into t_emp (emp_name,emp_salary,emp_age) values (?,?,?)";
        PreparedStatement prepareedStatement = connection.prepareStatement(sql);
        for(int i = 0;i<10000;i++){
            preparedStatement.setString(1,"marry"+i);
            preparedStatement.setDouble(2,100.0+i);
            preparedStatement.setInt(3,20+i):
            preparedStatement.addBatch():
        }
        preparedStatement.executeBatch();
        preparedStatement.close();
        connection.close();
    }
}

二、连接池

2.1现有问题:

(1)每次操作数据库都要获取新连接,使用完毕后就close释放,频繁的创建和销毁造成资源浪费;

(2)连接的数量无法把控,对服务器来说压力巨大。

2.2.连接池

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

2.3.常见连接池:

JDBC的数据库连接池使用javax.sql.DataSource接口进行规范,所有的第三方连接池都实现此接口,自行添加具体实现。也就是说,所有连接池获取连接的和回收连接方法都一样,不同的只有性能和扩展功能。

(1)DBCP是Apache提供的数据库连接池,速度相对C3P0较快,但自身存在一些BUG;

(2)C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以;

(3)Proxool是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3po差一点;

(4)Druid是阿里提供的数据库连接池,是集DBCP、C3P0、Proxool优点于一身的数据库连接池,性能、扩展性、易用性都更好,功能丰富;

(5)Hikari是SpringBoot2.x之后内置的一款连接池,基于 BoneCP(已经放弃维护,推荐该连接池)做了不少的改进和优化,口号是快速、简单、可靠;

2.4.Druid连接池使用:

(1)硬编码:

import com.alibaba.druid.pool.DruidDataSource;
public void druidHard()throws SQLException {
    //1.连接池对象
    DruidDataSource dataSource =new DruidDataSource();
    //2.设置四个必须参数
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUsername("root");
    dataSource.setPassword("atguigu");
    dataSource.setUrl("jdbc:mysql:///atguigu");
    //非必须
    dataSource.setInitialsize(5);//初始化数
    dataSource.setMaxActive(10);//最大数量
    //3.通过连接池获取连接
    Connection connection=dataSource.getConnection();
    // JDBC的步骤,正常curd
    //4.回收连接,此处不是释放,而是将连接放回池中
    connection.close();
}

(2)软编码:

在项目目录下创建resources文件夹,标识该文件夹为资源目录,创建db.properties配置文件,将连接信息定义在该文件中。

# druid连接池需要的配置参数,key固定命名
driyerClassName=com.mysql.cj.jdbc.Driver
username=root
password=atguigu
url=jdbc:mysql:///atguigu
initialSize=10
maxActive=20
public void druidSoft()throws Exception{
    //创建Properties集合,存储文件中的key=value
    Properties properties =new Properties();
    //借助类加载器获取文件的字节数入流
    InputStream ips=DruidTest.class.getClassLoader().getResourceAsStream("db.properties");
    //将流中的数据存储到集合中
    properties.load(ips);
    //读取Properties集合中的数据创建连接池
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    Connection connection=dataSource.getConnection();
    connection.close();
}

2.5.HikariCP连接池使用:

(1)硬编码方式:

import com.zaxxer.hikari.HikariDataSource;
public void testHardCodeHikari()throws SQLException {
    //1.创建HikariDataSource连接池对象
    HikariDataSource hikariDataSource = new HikariDataSource();
    //2.设置连接池的配置信息【必须|非必须】
    //2.1必须设置的配置
    hikariDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    hikariDataSource.setJdbcUrl("jdbc:mysql:///atguigu");
    hikariDataSource.setUsername("root");
    hikariDataSource.setPassword("atguigu");
    //2.2 非必须设置的配置
    hikariDataSource.setMinimumIdle(10);
    hikariDataSource.setMaximumPoolSize(20);
    //3.通过连接池获取连接对象
    Connection connection =hikariDataSource.getConnection();
    System.out.println(connection);
    //回收连接
    connection.close();
}

(2)软编码方式:

在项目目录下创建resources文件夹,标识该文件夹为资源目录,创建hikari.properties配置文件,将连接信息定义在该文件中。

driverClassName=com.mysql.cj.jdbc.Driver
jdbcUrl=jdbc:mysql:///atguigu
username=root
password=atguigu
minimumIdle=10
maximumPoolSize=20
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.创建HikariConfig连接池配置对象,将Properties集合传进去.
    HikariConfig hikariconfig = new Hikariconfig(properties);
    //4.基于HikariConfi连接池配置对象构建HikariDataSource
    HikariDataSource hikariDataSource = new HikariDataSource(hikariconfig);
    //5.获取连接
    Connection connection=hikariDataSource.getConnection();
    System.out.println(connection);
    //6.回收连接
    connection.close();
}
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值