JDBC基础



  1. JDBC原理
  2. JDBC基础编程

1. JDBC原理

1.1. JDBC标准

1.1.1. JDBC是什么

Java Database Connectivity:Java访问数据库的解决方案。

JDBC是Java应用程序访问数据库的里程碑式解决方案。Java研发者希望用相同的方式访问不同的数据库,以实现与具体数据库无关的Java操作界面。

JDBC定义了一套标准接口,即访问数据库的通用API,不同的数据库厂商根据各自数据库的特点去实现这些接口。

图-1应用、JDBC和数据库的关系

1.1.2. JDBC接口及数据库厂商实现

JDBC中定义了一些接口:

1、驱动管理:

  • DriverManager

2、连接接口

  • Connection
  • DatabasemetaData

3、语句对象接口

  • Statement
  • PreparedStatement
  • CallableStatement

4、结果集接口

  • ResultSet
  • ResultSetMetaData

1.1.3. JDBC工作原理

JDBC只定义接口,具体实现由各个数据库厂商负责。

程序员使用时只需要调用接口,实际调用的是底层数据库厂商的实现部分。

图-2 通过JDBC访问数据库的过程

JDBC访问数据库的工作过程:

  1. 加载驱动,建立连接
  2. 创建语句对象
  3. 执行SQL语句
  4. 处理结果集
  5. 关闭连接

1.1.4. Driver接口及驱动类加载

要使用JDBC接口,需要先将对应数据库的实现部分(驱动)加载进来。

驱动类加载方式(Oracle):

			
    
    
  1. Class.forName("oracle.jdbc.driver.OracleDriver");

这条语句的含义是:装载驱动类,驱动类通过static块实现在DriverManager中的“自动注册”。

1.1.5. Connection接口

Connection接口负责应用程序对数据库的连接,在加载驱动之后,使用url、username、password三个参数,创建到具体数据库的连接。

			
    
    
  1. Class.forName("oracle.jdbc.OracleDriver")
  2. //根据url连接参数,找到与之匹配的Driver对象,调用其方法获取连接
  3. Connection conn = DriverManager.getConnection(
  4. "jdbc:oracle:thin:@192.168.0.26:1521:tarena",
  5. "openlab","open123");

需要注意的是:Connection只是接口,真正的实现是由数据库厂商提供的驱动包完成的。

1.1.6. Statement接口

Statement接口用来处理发送到数据库的SQL语句对象,通过Connection对象创建。主要有三个常用方法:

			
    
    
  1. Statement stmt=conn.createStatement();
  2. //1.execute方法,如果执行的sql是查询语句且有结果集则返回true,如果是非查询语句或者没有结果集,返回false
  3. boolean flag = stmt.execute(sql);
  4. //2.执行查询语句,返回结果集
  5. ResultSetrs = stmt.executeQuery(sql);
  6. //3.执行DML语句,返回影响的记录数
  7. int flag = stmt.executeUpdate(sql);

1.1.7. ResultSet接口

执行查询SQL语句后返回的结果集,由ResultSet接口接收。

常用处理方式:遍历 / 判断是否有结果(登录)。


    
    
  1. String sql = "select * from emp";
  2. ResultSetrs = stmt.executeQuery(sql);
  3. while (rs.next()) {
  4.     System.out.println(rs.getInt("empno")+",“
  5. +rs.getString("ename") );
  6. }

查询的结果存放在ResultSet对象的一系列行中,指针的最初位置在行首,使用next()方法用来在行间移动,getXXX()方法用来取得字段的内容。

1.2. 数据库厂商实现

1.2.1. Oracle实现

在Java程序中访问不同数据库,需要下载对应数据库的驱动。Oracle数据库提供的驱动为ojdbc6.jar或者ojdbc14.jar,在开发时需要将驱动类加载到项目中,通过设置MyEclipse的Build Path选项。

使用时就可以如下方式加载驱动类了:


    
    
  1. Class.forName("oracle.jdbc.driver.OracleDriver");

1.2.2. MySQL实现

MySQL对应的数据库驱动名为mysql-connector-java-5.0.4-bin.jar(不同版本可能有不同名称),将驱动类加载到项目中同样通过设置MyEclipse的Build Path选项。

加载驱动类的方式:

			
    
    
  1. Class.forName("com.mysql.jdbc.Driver");

2. JDBC基础编程

2.1. 连接管理

2.1.1. 通过连接工具类获取连接

在工程中,通常编写一个访问数据库的工具类,此后所有访问数据库的操作,都从工具类中获取连接。

实现工具类的两种方式:

  • 直接把数据配置写在工具类。
  • 把数据库配置写在一个properties属性文件里,工具类读入属性文件,逐行获取数据库参数。

建议使用第二种。

2.1.2. 通过属性文件维护连接属性

db.properties的内容:

				
    
    
  1. #驱动类名
  2. jdbc.driver=oracle.jdbc.driver.OracleDriver
  3. #连接字符串
  4. jdbc.url=jdbc:oracle:thin:@192.168.0.26:1521:tarena
  5. #访问数据库的用户名
  6. jdbc.user=openlab
  7. #访问数据库的密码
  8. jdbc.password=open123

注意:在properties文件中,#符号表示注释。

2.1.3. 从类路径中加载属性文件

定义好db.properties之后,需要在Java程序中找到它,可以使用从类路径加载的方式:

			
    
    
  1. //属性文件所在的位置
  2. String path = "com/tarena/dms/daodemo/v2/db.properties";
  3. //获得当前类的路径,加载指定属性文件
  4. properties.load(DBUtility.class.getClassLoader()
  5. .getResourceAsStream(path));

2.1.4. 连接的关闭

在工具类中定义公共的关闭连接的方法,所有访问数据库的应用,共享此方法。当完成功能,关闭连接。

		
    
    
  1. protected static void closeConnection(Connection con) {
  2.         if (con != null) {
  3.             try {
  4.                 con.close();
  5.             } catch (SQLException e) {
  6. e.printStackTrace();
  7.             }
  8.         }
  9.     }

2.2. 连接池技术

2.2.1. 为什么要使用连接池

数据库连接的建立及关闭资源消耗巨大。传统数据库访问方式:一次数据库访问对应一个物理连接,每次操作数据库都要打开、关闭该物理连接, 系统性能严重受损。

解决方案:数据库连接池(Connection Pool)。

系统初始运行时,主动建立足够的连接,组成一个池.每次应用程序请求数据库连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不再关闭,而是归还。

图-3 连接池示意图

连接池中连接的释放与使用原则

  • 应用启动时,创建初始化数目的连接
  • 当申请时无连接可用或者达到指定的最小连接数,按增量参数值创建新的连接
  • 为确保连接池中最小的连接数的策略:
  1. 动态检查:定时检查连接池,一旦发现数量小于最小连接数,则补充相应的新连接,保证连接池正常运转
  2. 静态检查:空闲连接不足时,系统才检测是否达到最小连接数
  • 按需分配,用过归还,超时归还

连接池也只是JDBC中定义的接口,具体实现由厂商实完成。

2.2.2. 使用Apache DBCP连接池

DBCP(DataBase connection pool):数据库连接池,是Apache的一个 Java 连接池开源项目,同时也是 Tomcat 使用的连接池组件。相当于是Apache开发的针对连接池接口的一个实现方案。

连接池是创建和管理连接的缓冲池技术,将连接准备好被任何需要它们的应用使用。

图-4连接池在数据访问中的应用

使用Apache DBCP需要两个jar包文件:

  • commons-dbcp-1.4.jar 连接池的实现
  • commons-pool-1.5.jar 连接池实现的依赖库

将上述两个文件在MyEclipse的Build Path选项中导入到项目。

2.2.3. 通过DataSource获取连接

先通过属性文件获取连接池参数,然后加载这些参数,获得连接:

			
    
    
  1. //创建数据源对象
  2. private static BasicDataSourcedataSource = new BasicDataSource();
  3. //加载参数
  4. dataSource.setDriverClassName(driveClassName);
  5. dataSource.setUrl(url);
  6. dataSource.setUsername(username);
  7. dataSource.setPassword(password);
  8. //获得连接
  9. Connection conn = dataSource.getConnection();

2.2.4. 连接池参数

常用参数有:

  • 初始连接数
  • 最大连接数
  • 最小连接数
  • 每次增加的连接数
  • 超时时间
  • 最大空闲连接
  • 最小空闲连接

根据应用需要,设置合适的值。

2.3. 异常处理

2.3.1. SQLException简介

Java.sql.SQLException是在处理JDBC时常见的exception对象,用来表示JDBC操作过程中发生的具体错误;

一般的SQLException都是因为操作数据库时出错 , 比如Sql语句写错,或者数据库中的表或数据出错。

常见异常:

  • 登录被拒绝
  • 可能原因:程序里取键值对信息时的大小写和属性文件中不匹配
  • 列名无效
  • 可能原因:查找的表和查找的列不匹配
  • 无效字符
  • 可能原因:SQL语句语法有错 , 比如语句结尾时不能有分号
  • 无法转换为内部表示
  • 可能原因:结果集取数据时注意数据类型。
  • 表或者视图不存在
  • 检查SQL中的表名是否正确
  • 不能将空值插入
  • 检查执行insert操作时,是否表有NOT NULL约束,而没有给出数据
  • 缺少表达式
  • 检查SQL语句的语法
  • SQL 命令未正确结束
  • 检查SQL语句的语法
  • 无效数字:
  • 企图将字符串类型的值填入数字型而造成,检查SQL语句

其他可能出现的异常

  • 文件找不到
  • 可能原因:db.properties文件路径不正确

注意: 新增数据后务必要commit, 否则Java程序运行查询后找不到数据。

2.3.2. 处理SQLException

SQLException属于Checked Exception,必须使用try…catch或throws明确处理。

			
    
    
  1. public static synchronized Connection getConnection() throws SQLException {
  2. //语句,省略
  3. }

或者:


    
    
  1. try {
  2.     //语句,省略    
  3. } catch (SQLException e) {
  4.     e.printStackTrace();//追踪处理
  5. //throw new RuntimeException(e);//或者抛出
  6. }



  JDBC:java数据库连接

 * JDBC是一套标准的接口,规定了连接数据库的步骤与操作数据库的功能。
 * 不同的数据库提供商都提供了一套JDBC的实现类以操作该数据库,这一套实现类称为该数据库的驱动包。

 *JDBC中的主要接口:
 *DriverManager:负责加载驱动,建立与数据库的连接
 *Connection: 表示与数据库的一个连接,负责创建Statement
 *Statement:负责向数据库执行SQL语句

 *ResultSet:表示数据库的一个查询结果集


一、连接数据库过程

  1. 加载驱动,建立连接
  2. 创建语句对象
  3. 执行SQL语句
  4. 处理结果集
  5. 关闭连接


            /*
             * 1.加载驱动,不同的数据库字符串内容不一样
             */
            Class.forName("oracle.jdbc.driver.OracleDriver");
            /*
             * 2.使用DriverManager通过加载的驱动与数据库建立连接
             * DriverManager的静态方法getConnection用于与数据库建立连接,需要传入三个参数:
             * 参数1:数据库的地址(不同数据库的格式不一样)
             * 参数2:数据库的用户名
             * 参数3:数据库的密码
             * (在实际应用中,将参数写到配置文件中)
             */
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@176.225.131.254:1521:orcl",
                                        "tarena", 
                                        "tarena");
            System.out.println("已连接数据库!");
            /*
             * 3.创建Statement以发送SQL语句
             */
            Statement state = conn.createStatement();


二、针对不同数据库,Statement提供不同的方法

            /*
             * 针对不同的SQL语句,Statement也提供了相应的执行方法:
             * 1.int executeUpdate(String sql)
             *         专门用来执行DML语句的方法,返回值为一个数字
             *         表示执行DML操作后影响了表中的记录数
             * 
             * 2.ResultSet executeQuery(String sql)
             *         专门用来执行DQL语句的方法,返回值为一个ResultSet实例,
             *         表示DQL执行后的查询结果集
             * 
             * 3.boolean execute(String sql)
             *         可以执行所有类型的SQL语句,由于DML、DQL有专门的方法,所以通常使用execute方法来执行DDL语句。
             *         返回值为boolean值,当该值为true时,说明执行SQL后有查询结果集
             */


EG:    /*
             * 创建一张表:userinfo
             * 字段:    id NUMBER(6)
             *         username VARCHAR2(50)
             *         password VARCHAR2(50)
             *         email VARCHAR2(100)
             *         nickName VARCHAR2(50)
             *         account NUMBER(10,2)
             */
            String sql =  "CREATE TABLE userinfo_snow( "    //    后引号前面都加一个空格
                        + "    id NUMBER(6), "
                        + "    username VARCHAR2(50), "
                        + "    password VARCHAR2(50), "
                        + "    email VARCHAR2(100), "
                        + "    nickName VARCHAR2(50), "
                        + "    account NUMBER(10,2) "
                        +")";
            System.out.println(sql);
            state.execute(sql);            //执行DDL语句

EG:/**
 * 创建一个序列:
 * seq_userinfo_id
 * 从1开始,步进为1
 * @author Tarena-java
 *
 */
public class JDBCDemo02 {
    public static void main(String[] args) {
        try {
            
            //1.加载驱动
            Class.forName("oracle.jdbc.driver.OracleDriver");
            //2.DriverManager与数据库建立连接
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@176.225.131.254:1521:orcl","tarena","tarena");
            System.out.println("数据库连接成功!");
            //3.创建Statement发送SQL
            Statement state = conn.createStatement();
            //创建序列
            String sql = "CREATE SEQUENCE seq_userinfo_snow_id "
                    + "START WITH 1 "
                    + "INCREMENT BY 1 ";
            System.out.println(sql);
            state.execute(sql);
            System.out.println("执行成功!");
            conn.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

EG:/**
 * 执行DML语句
 * @author Tarena-java
 *
 */
public class JDBCDemo03 {
    public static void main(String[] args) {
        try {
            Scanner scan = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = scan.next();
            String password = null;
            while(true){
                System.out.println("请输入密码:");
                String password1 = scan.next();
                System.out.println("请再次输入密码:");
                String password2 = scan.next();
                if(password2.equals(password1)){
                    password = password1;
                    break;
                }
                System.out.println("两次密码不匹配,请重新输入!");
            }
            System.out.println("请输入邮箱:");
            String email = null;
            while(true){
                email = scan.next();
                String reg = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)";
                if(email.matches(reg)){
                    break;
                }else{
                    System.out.println("邮箱格式错误!请重新输入");
                }
            }
            
            System.out.println("请输入昵称");
            String nickName = scan.next();
            
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@176.225.131.254:1521:orcl","tarena","tarena");
            System.out.println("连接成功!");
            Statement state = conn.createStatement();
            String sql = "INSERT INTO userinfo_snow "
                       + "(id,username,password,email,nickName,ACCOUNT) "
                       + "VALUES "
                       + "(seq_userinfo_snow_id.NEXTVAL"+",'"+username+"','"+password+"','"+email+"','"+nickName+"',+8000) ";
            System.out.println(sql);
            int i = state.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功!");
            }
            state.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

EG:

/**
 * 执行DQL语句
 * @author Tarena-java
 *
 */
public class JDBCDemo04 {
    public static void main(String[] args) {
        
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@176.225.131.254:1521:orcl", "tarena", "tarena");
            Statement state = conn.createStatement();
            System.out.println("已连接到数据库!");
            String sql = "SELECT id,username,password,email,nickName,account "
                    + "FROM userinfo_snow";
            ResultSet rs = state.executeQuery(sql);
            /*
             * java.sql.ResultSet
             * 表示一个数据库的查询结果集:ResultSet提供了遍历结果集的相关方法
             * boolean next()
             * 判断结果集是否还有下一条记录,若有则返回true,并使当前ResultSet的指针指向并表示该条(下一条)记录。
             * 若没有则返回false
             * 
             * 提供了若干的getxxx(String colName)方法,根据字段名获取该字段对应的值,
             * 不同字段类型使用不同的方法(getString、getInt...)
             */
            while(rs.next()){
                int id = rs.getInt("id");    
                String username = rs.getString("username");
                String password = rs.getString("password");
                String email = rs.getString("email");
                String nickName = rs.getString("nickName");
                int account = rs.getInt("account");
                System.out.println(id+","+username+","+password+","+email+","+nickName+","+account);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


EG:

/**
 * 输入每页显示的条数以及显示第几页,然后输出emp表中对应的记录
 * 字段查询:empno,ename,sal,job,deptno
 * 要求是按照工资降序排列后的分页
 * @author Tarena-java
 *
 */
public class JDBCDemo05 {
    public static void main(String[] args) {
        try {
            Scanner scan = new Scanner(System.in);
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@176.225.131.254:1521:orcl", "tarena", "tarena");
            Statement state = conn.createStatement();
            System.out.println("请输入显示的页数:");
            int page = scan.nextInt();
            System.out.println("请输入每页显示的条数:");
            int pageSize = scan.nextInt();
            int start = (page-1)*pageSize + 1;
            int end = pageSize*page;
            //分页查询语言
            String sql = "SELECT * "
                        + "    FROM (SELECT ROWNUM rn,t.* "
                        + "        FROM (SELECT empno,ename,sal,job,deptno "
                        + "            FROM emp_snow "
                        + "            ORDER BY sal DESC ) t "
                        + "        WHERE ROWNUM <= "+end+" ) "
                        + "WHERE rn >= "+start;
                        //+ " WHERE rn BETWEEN "+start+" AND "+end;
            ResultSet rs = state.executeQuery(sql);        
            while(rs.next()){
                int empno = rs.getInt("empno");    
                String ename = rs.getString("ename");
                int sal = rs.getInt("sal");
                String job = rs.getString("job");
                int deptno = rs.getInt("deptno");
                System.out.println(empno+","+ename+","+sal+","+job+","+deptno);
            }
            conn.close();
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}












  1. JDBC原理
  2. JDBC基础编程

1. JDBC原理

1.1. JDBC标准

1.1.1. JDBC是什么

Java Database Connectivity:Java访问数据库的解决方案。

JDBC是Java应用程序访问数据库的里程碑式解决方案。Java研发者希望用相同的方式访问不同的数据库,以实现与具体数据库无关的Java操作界面。

JDBC定义了一套标准接口,即访问数据库的通用API,不同的数据库厂商根据各自数据库的特点去实现这些接口。

图-1应用、JDBC和数据库的关系

1.1.2. JDBC接口及数据库厂商实现

JDBC中定义了一些接口:

1、驱动管理:

  • DriverManager

2、连接接口

  • Connection
  • DatabasemetaData

3、语句对象接口

  • Statement
  • PreparedStatement
  • CallableStatement

4、结果集接口

  • ResultSet
  • ResultSetMetaData

1.1.3. JDBC工作原理

JDBC只定义接口,具体实现由各个数据库厂商负责。

程序员使用时只需要调用接口,实际调用的是底层数据库厂商的实现部分。

图-2 通过JDBC访问数据库的过程

JDBC访问数据库的工作过程:

  1. 加载驱动,建立连接
  2. 创建语句对象
  3. 执行SQL语句
  4. 处理结果集
  5. 关闭连接

1.1.4. Driver接口及驱动类加载

要使用JDBC接口,需要先将对应数据库的实现部分(驱动)加载进来。

驱动类加载方式(Oracle):

			
     
     
  1. Class.forName("oracle.jdbc.driver.OracleDriver");

这条语句的含义是:装载驱动类,驱动类通过static块实现在DriverManager中的“自动注册”。

1.1.5. Connection接口

Connection接口负责应用程序对数据库的连接,在加载驱动之后,使用url、username、password三个参数,创建到具体数据库的连接。

			
     
     
  1. Class.forName("oracle.jdbc.OracleDriver")
  2. //根据url连接参数,找到与之匹配的Driver对象,调用其方法获取连接
  3. Connection conn = DriverManager.getConnection(
  4. "jdbc:oracle:thin:@192.168.0.26:1521:tarena",
  5. "openlab","open123");

需要注意的是:Connection只是接口,真正的实现是由数据库厂商提供的驱动包完成的。

1.1.6. Statement接口

Statement接口用来处理发送到数据库的SQL语句对象,通过Connection对象创建。主要有三个常用方法:

			
     
     
  1. Statement stmt=conn.createStatement();
  2. //1.execute方法,如果执行的sql是查询语句且有结果集则返回true,如果是非查询语句或者没有结果集,返回false
  3. boolean flag = stmt.execute(sql);
  4. //2.执行查询语句,返回结果集
  5. ResultSetrs = stmt.executeQuery(sql);
  6. //3.执行DML语句,返回影响的记录数
  7. int flag = stmt.executeUpdate(sql);

1.1.7. ResultSet接口

执行查询SQL语句后返回的结果集,由ResultSet接口接收。

常用处理方式:遍历 / 判断是否有结果(登录)。


     
     
  1. String sql = "select * from emp";
  2. ResultSetrs = stmt.executeQuery(sql);
  3. while (rs.next()) {
  4.     System.out.println(rs.getInt("empno")+",“
  5. +rs.getString("ename") );
  6. }

查询的结果存放在ResultSet对象的一系列行中,指针的最初位置在行首,使用next()方法用来在行间移动,getXXX()方法用来取得字段的内容。

1.2. 数据库厂商实现

1.2.1. Oracle实现

在Java程序中访问不同数据库,需要下载对应数据库的驱动。Oracle数据库提供的驱动为ojdbc6.jar或者ojdbc14.jar,在开发时需要将驱动类加载到项目中,通过设置MyEclipse的Build Path选项。

使用时就可以如下方式加载驱动类了:


     
     
  1. Class.forName("oracle.jdbc.driver.OracleDriver");

1.2.2. MySQL实现

MySQL对应的数据库驱动名为mysql-connector-java-5.0.4-bin.jar(不同版本可能有不同名称),将驱动类加载到项目中同样通过设置MyEclipse的Build Path选项。

加载驱动类的方式:

			
     
     
  1. Class.forName("com.mysql.jdbc.Driver");

2. JDBC基础编程

2.1. 连接管理

2.1.1. 通过连接工具类获取连接

在工程中,通常编写一个访问数据库的工具类,此后所有访问数据库的操作,都从工具类中获取连接。

实现工具类的两种方式:

  • 直接把数据配置写在工具类。
  • 把数据库配置写在一个properties属性文件里,工具类读入属性文件,逐行获取数据库参数。

建议使用第二种。

2.1.2. 通过属性文件维护连接属性

db.properties的内容:

				
     
     
  1. #驱动类名
  2. jdbc.driver=oracle.jdbc.driver.OracleDriver
  3. #连接字符串
  4. jdbc.url=jdbc:oracle:thin:@192.168.0.26:1521:tarena
  5. #访问数据库的用户名
  6. jdbc.user=openlab
  7. #访问数据库的密码
  8. jdbc.password=open123

注意:在properties文件中,#符号表示注释。

2.1.3. 从类路径中加载属性文件

定义好db.properties之后,需要在Java程序中找到它,可以使用从类路径加载的方式:

			
     
     
  1. //属性文件所在的位置
  2. String path = "com/tarena/dms/daodemo/v2/db.properties";
  3. //获得当前类的路径,加载指定属性文件
  4. properties.load(DBUtility.class.getClassLoader()
  5. .getResourceAsStream(path));

2.1.4. 连接的关闭

在工具类中定义公共的关闭连接的方法,所有访问数据库的应用,共享此方法。当完成功能,关闭连接。

		
     
     
  1. protected static void closeConnection(Connection con) {
  2.         if (con != null) {
  3.             try {
  4.                 con.close();
  5.             } catch (SQLException e) {
  6. e.printStackTrace();
  7.             }
  8.         }
  9.     }

2.2. 连接池技术

2.2.1. 为什么要使用连接池

数据库连接的建立及关闭资源消耗巨大。传统数据库访问方式:一次数据库访问对应一个物理连接,每次操作数据库都要打开、关闭该物理连接, 系统性能严重受损。

解决方案:数据库连接池(Connection Pool)。

系统初始运行时,主动建立足够的连接,组成一个池.每次应用程序请求数据库连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不再关闭,而是归还。

图-3 连接池示意图

连接池中连接的释放与使用原则

  • 应用启动时,创建初始化数目的连接
  • 当申请时无连接可用或者达到指定的最小连接数,按增量参数值创建新的连接
  • 为确保连接池中最小的连接数的策略:
  1. 动态检查:定时检查连接池,一旦发现数量小于最小连接数,则补充相应的新连接,保证连接池正常运转
  2. 静态检查:空闲连接不足时,系统才检测是否达到最小连接数
  • 按需分配,用过归还,超时归还

连接池也只是JDBC中定义的接口,具体实现由厂商实完成。

2.2.2. 使用Apache DBCP连接池

DBCP(DataBase connection pool):数据库连接池,是Apache的一个 Java 连接池开源项目,同时也是 Tomcat 使用的连接池组件。相当于是Apache开发的针对连接池接口的一个实现方案。

连接池是创建和管理连接的缓冲池技术,将连接准备好被任何需要它们的应用使用。

图-4连接池在数据访问中的应用

使用Apache DBCP需要两个jar包文件:

  • commons-dbcp-1.4.jar 连接池的实现
  • commons-pool-1.5.jar 连接池实现的依赖库

将上述两个文件在MyEclipse的Build Path选项中导入到项目。

2.2.3. 通过DataSource获取连接

先通过属性文件获取连接池参数,然后加载这些参数,获得连接:

			
     
     
  1. //创建数据源对象
  2. private static BasicDataSourcedataSource = new BasicDataSource();
  3. //加载参数
  4. dataSource.setDriverClassName(driveClassName);
  5. dataSource.setUrl(url);
  6. dataSource.setUsername(username);
  7. dataSource.setPassword(password);
  8. //获得连接
  9. Connection conn = dataSource.getConnection();

2.2.4. 连接池参数

常用参数有:

  • 初始连接数
  • 最大连接数
  • 最小连接数
  • 每次增加的连接数
  • 超时时间
  • 最大空闲连接
  • 最小空闲连接

根据应用需要,设置合适的值。

2.3. 异常处理

2.3.1. SQLException简介

Java.sql.SQLException是在处理JDBC时常见的exception对象,用来表示JDBC操作过程中发生的具体错误;

一般的SQLException都是因为操作数据库时出错 , 比如Sql语句写错,或者数据库中的表或数据出错。

常见异常:

  • 登录被拒绝
  • 可能原因:程序里取键值对信息时的大小写和属性文件中不匹配
  • 列名无效
  • 可能原因:查找的表和查找的列不匹配
  • 无效字符
  • 可能原因:SQL语句语法有错 , 比如语句结尾时不能有分号
  • 无法转换为内部表示
  • 可能原因:结果集取数据时注意数据类型。
  • 表或者视图不存在
  • 检查SQL中的表名是否正确
  • 不能将空值插入
  • 检查执行insert操作时,是否表有NOT NULL约束,而没有给出数据
  • 缺少表达式
  • 检查SQL语句的语法
  • SQL 命令未正确结束
  • 检查SQL语句的语法
  • 无效数字:
  • 企图将字符串类型的值填入数字型而造成,检查SQL语句

其他可能出现的异常

  • 文件找不到
  • 可能原因:db.properties文件路径不正确

注意: 新增数据后务必要commit, 否则Java程序运行查询后找不到数据。

2.3.2. 处理SQLException

SQLException属于Checked Exception,必须使用try…catch或throws明确处理。

			
     
     
  1. public static synchronized Connection getConnection() throws SQLException {
  2. //语句,省略
  3. }

或者:


     
     
  1. try {
  2.     //语句,省略    
  3. } catch (SQLException e) {
  4.     e.printStackTrace();//追踪处理
  5. //throw new RuntimeException(e);//或者抛出
  6. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值