JDBC介绍

一.它是什么?
是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
简单理解为:JDBC,是SUN提供的一套 API,使用这套API可以实现对具体数据库的操作(获取连接、关闭连接、DML、DDL、DCL)

二.为什么要用?
使用它将是为了数据的持久化
数据持久化:将内存中的数据永久的保存在硬盘上,该过程则需要通过各种关系数据库来完成,主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中

三.好处
面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)
面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用
从开发程序员的角度:不需要关注具体的数据库的细节
数据库厂商:只需要提供标准的具体实现。

四.图示理解

五.编写步骤
在这里插入图片描述
以下是我使用的版本

@Test
    public void test1() throws Exception {
        //获取到输入流
        //读取配置的四个信息  
        //connection.class.getClassLoader()获取类的加载器 = ClassLoader.getSystemClassLoader()
        // getSystemClassLoader():返回用于委派的系统类加载器  
        //getResourceAsStream(): 用于读取资源的输入流; null如果找不到该资源,该资源是在一个未被无条件打开的包中,或该资源的访问被安全管理器拒绝。
        InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        //使用Properties获取到其对应信息
        Properties pop = new Properties();
        //pop从什么里面拿取到
        pop.load(inputStream);
        //设置接收
        String user = pop.getProperty("user");
        String password = pop.getProperty("password");
        //相当于进入网页的链接 jdbc:mysql://localhost:3306/myemployees jdbc:mysql:相当于http localhost:端口号  3306:ip地址  myemployees:需要链接的数据库名
        String url = pop.getProperty("url");
        //设置驱动
        String driverclass = pop.getProperty("driverClass");
        //中间其实省略了加载驱动的过程
        //{
        //DriverManager:用于管理一组JDBC驱动程序的基本服务,初始化完成懒惰,并使用线程上下文类加载器查找服务提供程序。 加载并可用于应用程序的驱动程序将取决于通过,触发驱动程序初始化的线程的线程上下文类加载器。
        Class<?> aClass = Class.forName(driverclass);
        //通过类的暴力反射获取到驱动的对象再强转
        Driver driver = (Driver) aClass.newInstance();
        //registerDriver(Driver driver):新加载的驱动程序类应该调用方法registerDriver使其自己已知DriverManager 。 如果司机目前已注册,则不采取任何行动。
        DriverManager.registerDriver(driver);
        //}
        //加载完后就要开始链接
        //getConnection(String url, String user, String password):尝试建立与给定数据库URL的连接。 DriverManager尝试从一组已注册的JDBC驱动程序中选择适当的驱动程序。
        // url - 表单 jdbc:subprotocol:subname的数据库URL
        //user - 正在进行连接的数据库用户
        //password - 用户密码
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

我使用的是maven项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>pro2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
</project>

其配置文件为:
在这里插入图片描述
要素介绍:
Driver接口介绍:

  • java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
  • 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。
    • Oracle的驱动:oracle.jdbc.driver.OracleDriver
    • mySql的驱动: com.mysql.jdbc.Driver

加载与注册JDBC驱动:
加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名

  • Class.forName(“com.mysql.jdbc.Driver”);

注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序

  • 使用DriverManager.registerDriver(com.mysql.jdbc.Driver)来注册驱动
  • 通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,因为 Driver 接口的驱动程序类包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注册自身的一个实例。下图是MySQL的Driver实现类的源码:

URL介绍:
用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
URL的标准由三部分组成,各部分间用冒号分隔。
在这里插入图片描述
用户名和密码:
user,password可以用“属性名=属性值”方式告诉数据库
可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接

六.使用PreparedStatement实现CRUD操作
1.简单来说,要实现对数据的CRUD,其根本就是我们java上编写相关语言,数据库接受其命令边反馈其相关语言操作的结果,其实一个数据库连接就是一个Socket连接。
在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

  • Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
  • PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
  • CallableStatement:用于执行 SQL 存储过程
    在这里插入图片描述
    2.使用Statement操作数据表的弊端:
    存在拼串操作,繁琐:SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。
    存在SQL注入问题:Statement不会识别占位符,就从具体的某一个位置开始,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。

3.PreparedStatement的使用
介绍:PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

4.PreparedStatement vs Statement
代码的可读性和可维护性;
PreparedStatement 能最大可能提高性能:
DBServer会对预编译语句提供性能优化,固存在预编译的语句会被重复使用,使用PreparedStatement 语句会做到预编译,降低了系统的响应时间,并且会形成缓存,下次再执行的时候就不会都去再匹配一次;
而在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次,使系统响应时间增加,降低了效率。

5.ResultSet与ResultSetMetaData
ResultSet:
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现;
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现;

ResultSetMetaData:
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象

  • getColumnName(int column):获取指定列的名称
  • getColumnLabel(int column):获取指定列的别名
  • getColumnCount():返回当前 ResultSet 对象中的列数。
    在这里插入图片描述
    以下是一些通用的:
package Connections.Connections;

import org.junit.Test;
import util.JDBCUtils;

import java.lang.reflect.Field;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author BaBa
 * @Version 1/0
 * 操作数据库:
 * 1.链接
 * 2.操作
 * (1)传入操作语句(数据库的增删改查语句),这里必须使用占位符代替传入的值
 * (2)使用链接的方法prepareStatement(),写入具体操作的sql语句再创建对象
 * (3)使用上面创建的对象调用方法setObject(parameterLndex,x) parameterLndex:每列中位置,x:内容
 * (4)prepareStatement.execute 提交其数据
 * (5)最后释放资源(和io流一样,close())
 */
public class  connectionTest {
    //增加
    @Test
    public void Test() {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = JDBCUtils.getConnection();
//        System.out.println(connection);
            //5.预编译sql语句,返回PreparedStatemen的实例
            String sql = "insert into customers(name,email,date)values(?,?,?)";//?占位符,解决Statement的弊端
            statement = connection.prepareStatement(sql);
            //填充占位符
            statement.setString(1, "傻逼");
            statement.setString(2, "1314520@qq.com");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd");
            Date parse = simpleDateFormat.parse("2001-12-06");
            statement.setDate(3, new java.sql.Date(parse.getTime()));
//            statement.setDate(3,null);
            statement.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(connection, statement);
        }

    }

    //修改
    @Test
    public void TsetUpdate() {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            //1.获取连接
            connection = JDBCUtils.getConnection();
            //2.预编译sql语句,返回PreparedStatement的实例
            String sql = "update customers set name =? where id =?";
            //3.填充占位符
            ps = connection.prepareStatement(sql);
            ps.setObject(1, "周强");
            ps.setObject(2, 2);
            //4.执行
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.资源关闭
            JDBCUtils.closeResource(connection, ps);
        }
    }

    //通用
    public void updateDemo(String sql, Object... args) {//sql中占位符的个数与形参的长度一致
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            //获取连接
            connection = JDBCUtils.getConnection();
            //预编译sql
            ps = connection.prepareStatement(sql);
            //填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //提交
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JDBCUtils.closeResource(connection, ps);
        }
    }

    @Test
    public void testUpdate() {
        String sql = "delete from customers where id = ?";
        updateDemo(sql, 1);

        String sql1 = "update users set userid=? where id = ?";
        updateDemo(sql1, "王五", 3);
    }


    //查找
    @Test
    public void select() {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "select id,userid,department_id from users where id = ?";
            ps = connection.prepareStatement(sql);
            ps.setObject(1, 1);
            //执行并返回结果集
            resultSet = ps.executeQuery();
            //处理结果集
            if (resultSet.next()) {//判断结果集得到下一条有没有数据,如果为true,就往下移动,如果是false,就不往下移
                int anInt = resultSet.getInt(1);
                String string = resultSet.getString(2);
                int anInt1 = resultSet.getInt(3);
                Uers uers = new Uers(anInt, string, anInt1);
                System.out.println(uers);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResourceSelect(connection, ps, resultSet);
        }
    }


    @Test
    public void test() {
        String sql = "select id,userid,department_id from users where id < ?";
        List<Uers> uers = querUsers(Uers.class, sql, 3);
        uers.forEach(System.out::println);

    }
//    单个返回值对象
    public <T> T querUser(Class<T> tClass, String sql,Object...args)  {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            //预编译sql语句
            ps = connection.prepareStatement(sql);
            for (int i=0;i< args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //执行查询,返回结果集
            resultSet = ps.executeQuery();

            //获取结果集的元数据(封装在元数据中)
            ResultSetMetaData metaData = resultSet.getMetaData();

            //通过ResultSetMetaData获取结果集中列数(获取列数)
            int columnCount = metaData.getColumnCount();

            if (resultSet.next()){
                T t = tClass.newInstance();
                for (int i=0;i<columnCount;i++){
                    //值
                    Object values = resultSet.getObject(i + 1);

                    //获取每列的列名 ---不使用
//                    String catalogName = metaData.getColumnName(i + 1);
                    //表的字段名和类的属性名不相同的情况下:
                    // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名;
                    // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名
                    //获取列的别名
                    String label = metaData.getColumnLabel(i + 1);
                    //给Uers对象指定的catalogName属性赋值为values,通过反射
                    Field field = Uers.class.getDeclaredField(label);
                    field.setAccessible(true);
                    field.set(t,values);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResourceSelect(connection,ps,resultSet);
        }
        return null;
    }
    //多个返回值对象
    public <T>List<T> querUsers(Class<T> tClass, String sql, Object... args) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            //预编译sql语句
            ps = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //执行查询,返回结果集
            resultSet = ps.executeQuery();

            //获取结果集的元数据(封装在元数据中)
            ResultSetMetaData metaData = resultSet.getMetaData();

            //通过ResultSetMetaData获取结果集中列数(获取列数)
            int columnCount = metaData.getColumnCount();

            //不同于一个返回值对象,这里使用了while,把多个满足条件的放入数组中返回
            //创建集合对象
            ArrayList<T> list = new ArrayList<T>();
            while (resultSet.next()) {
                T t = tClass.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    //值
                    Object values = resultSet.getObject(i + 1);

                    //获取每列的列名 ---不使用
//                    String catalogName = metaData.getColumnName(i + 1);
                    //表的字段名和类的属性名不相同的情况下:
                    // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名;
                    // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名
                    //获取列的别名
                    String label = metaData.getColumnLabel(i + 1);
                    //给Uers对象指定的catalogName属性赋值为values,通过反射
                    Field field = Uers.class.getDeclaredField(label);
                    field.setAccessible(true);
                    field.set(t, values);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResourceSelect(connection, ps, resultSet);
        }
        return null;
    }
}

在这里插入图片描述

注意:使用了反射的技术,通过反射,创建指定类的对象,获取指定的属性并赋值

6.资源的释放
数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。

六.操作BLOB类型字段
1.介绍:MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
在这里插入图片描述
注意:
实际使用中根据需要存入的数据大小定义不同的BLOB类型。
需要注意的是:如果存储的文件过大,数据库的性能会下降。
如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

代码展示:

//插入Blob类型字段
    @Test
    public void insert() throws Exception {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into customers(name,email,photo) values(?,?,?);";
        PreparedStatement ps = connection.prepareStatement(sql);
        ps.setObject(1,"王五");
        ps.setObject(2,"2751190438@qq.com");
        FileInputStream is = new FileInputStream(new File("aa.jpg"));
        ps.setBlob(3,is);
        ps.execute();
        JDBCUtils.closeResource(connection,ps);
    }
//查询图片
    @Test
    public void Query()  {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        InputStream is =null;
        FileOutputStream fos =null;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "select id,name,email,photo from customers where id =?";
            ps = connection.prepareStatement(sql);
            ps.setObject(1,3);
            rs = ps.executeQuery();
            if (rs.next()){
                int id = rs.getInt(1);
                String name = rs.getString(2);
                String email = rs.getString(3);
                //接下来就是把值放到对象中XXX X = new xxx(id,name,email,photo);
                Blob photo = rs.getBlob(4);
                //将Blob字段下载下来保存到本地
                is = photo.getBinaryStream();
                fos = new FileOutputStream("zhangyuhao.jpg");
                byte[] bytes = new byte[1024];
                int len;
                while ((len=is.read(bytes))!=-1){
                    fos.write(bytes,0,len);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            JDBCUtils.closeResourceSelect(connection,ps,rs);
            try {
                if (is!=null)
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fos!=null)
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

七.批量插入
JDBC的批量处理语句包括下面三个方法:

  • addBatch(String):添加需要批量处理的SQL语句或是参数;
  • executeBatch():执行批量处理语句;
  • clearBatch():清空缓存的数据
//进阶批量插入
    //修改1: 使用 addBatch() / executeBatch() / clearBatch()
    //修改2:mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
    @Test
    public void insert3()  {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            long start = System.currentTimeMillis();
            connection = JDBCUtils.getConnection();

            //设置不允许自动提交
            connection.setAutoCommit(false);

            String sql = "insert into goods(name)values(?)";
            ps = connection.prepareStatement(sql);
            for (int i=1;i<=100;i++){
                ps.setObject(1,"name_"+i);

                //1.攒sql
                ps.addBatch();
                if (i%10==0){
                    //2.执行
                    ps.executeBatch();
                    //3.清空
                    ps.clearBatch();
                }
            }
            //提交
            connection.commit();
            long end = System.currentTimeMillis();
            System.out.println(end-start);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(connection,ps);
        }
    }

八.事务
1.介绍
一组逻辑操作单元,使数据从一种状态变换到另一种状态。
一组逻辑操作单元:一个或多个DML操作。

2.事务处理的原则:
保证所事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。

3.代码体现
考虑到事务以后,实现的通用的增删改操作:

//通用修改
    public void update(Connection connection, String sql, Object... args) {//sql中占位符的个数与形参的长度一致
        PreparedStatement ps = null;
        try {
            //预编译sql
            ps = connection.prepareStatement(sql);
            //填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //提交
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JDBCUtils.closeResource(null, ps);
        }
    }

考虑到事务以后,实现的通用的查询:

//通用查询
    public <T> T querUser(Connection connection, Class<T> tClass, String sql,Object...args)  {
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            //预编译sql语句
            ps = connection.prepareStatement(sql);
            for (int i=0;i< args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //执行查询,返回结果集
            resultSet = ps.executeQuery();

            //获取结果集的元数据(封装在元数据中)
            ResultSetMetaData metaData = resultSet.getMetaData();

            //通过ResultSetMetaData获取结果集中列数(获取列数)
            int columnCount = metaData.getColumnCount();

            if (resultSet.next()){
                T t = tClass.newInstance();
                for (int i=0;i<columnCount;i++){
                    //值
                    Object values = resultSet.getObject(i + 1);

                    //获取每列的列名 ---不使用
//                    String catalogName = metaData.getColumnName(i + 1);
                    //表的字段名和类的属性名不相同的情况下:
                    // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名;
                    // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名
                    //获取列的别名
                    String label = metaData.getColumnLabel(i + 1);
                    //给Uers对象指定的catalogName属性赋值为values,通过反射
                    Field field = Uers.class.getDeclaredField(label);
                    field.setAccessible(true);
                    field.set(t,values);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResourceSelect(null,ps,resultSet);
        }
        return null;
    }

4.属性以及会出现的问题
在这里插入图片描述
数据操作过程中可能出现的问题:(针对隔离性)
在这里插入图片描述

数据库的四种隔离级别:(一致性和并发性:一致性越好,并发性越差)
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
在这里插入图片描述
在这里插入图片描述

如何在Mysql中查看并设置隔离级别:
在这里插入图片描述
九.数据库连接池
1.传统连接的问题:
在这里插入图片描述
2.如何解决传统开发中的数据库连接问题:使用数据库连接池

3.介绍
数据库连接池的基本思想:- 就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去 。
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
工作原理:
在这里插入图片描述

4.使用数据库连接池的好处
资源重用:有需要就从数据库连接池拿出来用,避免了频繁创建,释放连接引起的大量性能开销。
更快的系统反应速度:有备用的链接,初始化的工作已经完成,可以很快速的响应连接。
新的资源分配手段:可以对某一层的连接数量进行限制,避免了某一应用独占所有的数据库资源。
统一的连接管理,避免数据库连接泄漏:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。

5.标准接口:DataSource
DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度

6.三种不同的使用连接池情况
C3P0

/**
	 * 
	 * @Description 使用C3P0的数据库连接池技术
	 * @author shkstart
	 * @date 下午3:01:25
	 * @return
	 * @throws SQLException
	 */
	//数据库连接池只需提供一个即可。
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");
	public static Connection getConnection1() throws SQLException{
		Connection conn = cpds.getConnection();
		
		return conn;
	}

其中,配置文件定义在src下。名为:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

	<named-config name="hellc3p0">
		<!-- 提供获取连接的4个基本信息 -->
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///test</property>
		<property name="user">root</property>
		<property name="password">abc123</property>
		
		<!-- 进行数据库连接池管理的基本信息 -->
		<!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 -->
		<property name="acquireIncrement">5</property>
		<!-- c3p0数据库连接池中初始化时的连接数 -->
		<property name="initialPoolSize">10</property>
		<!-- c3p0数据库连接池维护的最少连接数 -->
		<property name="minPoolSize">10</property>
		<!-- c3p0数据库连接池维护的最多的连接数 -->
		<property name="maxPoolSize">100</property>
		<!-- c3p0数据库连接池最多维护的Statement的个数 -->
		<property name="maxStatements">50</property>
		<!-- 每个连接中可以最多使用的Statement的个数 -->
		<property name="maxStatementsPerConnection">2</property>

	</named-config>
</c3p0-config>

DBCP
测试连接的代码:

/**
	 * 
	 * @Description 使用DBCP数据库连接池技术获取数据库连接
	 * @author shkstart
	 * @date 下午3:35:25
	 * @return
	 * @throws Exception
	 */
	//创建一个DBCP数据库连接池
	private static DataSource source;
	static{
		try {
			Properties pros = new Properties();
			FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));
			pros.load(is);
			source = BasicDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConnection2() throws Exception{
		
		Connection conn = source.getConnection();
		
		return conn;
	}

其中,配置文件定义在src下:dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=abc123
initialSize=10

Druid
Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。

/**
	 * 使用Druid数据库连接池技术
	 */
	private static DataSource source1;
	static{
		try {
			Properties pros = new Properties();
			
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
			
			pros.load(is);
			
			source1 = DruidDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConnection3() throws SQLException{
		
		Connection conn = source1.getConnection();
		return conn;
	}

配置文件:
url=jdbc:mysql:///test
username=root
password=abc123
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=10

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值