zoukankan      html  css  js  c++  java
  • Java数据库编程

    1. 数据库编程基本流程

      (1)加载数据库厂商的驱动程序

      例如:对于Mysql数据库,Class.forName("com.mysql.jdbc.Driver");

      (2)获得数据库连接对象

      Connection connection = DriverManager.getConnection(url,username,password);

      (3)创建数据库执行语句对象

      Statement  statement = connection.createStatement();

      (4)执行SQL语句,获得结果集对象

      ResultSet result = statement.executeQuery("SELECT * FROM tb_test");

      (5)关闭数据库连接

      使用完ResultSet、Statement以及Connection对象后,需要及时调用它们的close方法来释放资源。关闭Statement对象时,会自动释放由其获得的所有ResultSet对象,关闭Connection对象也会自动释放由其获得的Statement对象。因此,调用Connection的close方法就可以释放与其相关的所有资源。

      由于数据库连接使用完后必须关闭,因此通常将调用close方法放在finally子句中。

    2. JDBC获取自增主键

      很多时候,我们插入一个记录的主键是自增的列,我们可能紧接着需要获得这个主键,JDBC提供了统一的接口:

      statement.executeUpdate("INSERT....",Statement.RETURN_GENERATED_KEYS);

      ResultSet result = statement.getGeneratedKeys();

      其中,参数Statement.RETURN_GENERATED_KEYS指定返回刚插入的键,然后调用getGeneratedKeys方法返回这些键。

    3. 执行事务

      事务表示具有原子性的SQL语句的组合,这些SQL语句要么全部执行成功,要么就全部不执行。

      默认情况下,我们创建的Connection对象处于自动提交模式,即执行了一条SQL更新语句,就立即提交更新数据库。执行事务时,我们需要设置Connection对象不自动提交:connection.setAutoCommit(false);

      然后我们就可以执行多条SQL更新语句,这些对数据库的更新只有在调用Connection对象的commit方法后才会生效,如果执行这些SQL语句中出现了错误,就调用rollback方法回滚数据库。

    4. 数据库连接池

      当在多线程环境下进行数据库编程时,就需要注意同步的问题。

      使用一个全局的Connection对象若不进行同步就会导致并发的各种问题,而对这个全局Connection进行同步,通常效率又是很低的。我们可以使用局部的Connection对象,每次执行数据库任务时都创建一个新的连接,使用完后立即关闭,这样会导致频繁的创建关闭数据库连接,效率也会比较低。

      更好的方式使用数据库连接池来管理数据库连接,数据库连接池可以有效地利用闲置的数据库连接。想要连接数据库时,通过数据库连接池请求一个Connection对象,这个Connection可能是新创建的,也可能是之前创建尚未关闭的。关闭Connection对象时并不是真的与数据库断开连接,而是归入到数据库连接池的闲置连接中。

      实现一个数据库连接池最重要的问题就是解决调用Connection的close方法时,如何不真正关闭数据库连接。我们可以使用Java动态代理来解决这个问题。

      由于Connection是一个接口,而DriverManager.getConnection方法返回的Connection的具体类型我们又不知道,我们就无法直接通过覆盖来实现新的close方法。我们当然也可以自己实现Conneciton接口,但这样我们就需要实现许多接口方法,而实际上我们只需要改变close方法的实现。

      Java反射库中的Proxy类为我们提供了这样的能力:可以构造一个实现一些接口的类,并指定一个调用处理器(实现InvocationHandler接口)来拦截对所有接口方法的调用。

      下面给出一个简易实现的数据库连接池:

    public class DBConnectionPool
    {
        private String jdbcUrl;
        private String username;
        private String password;
        private LinkedList<Connection> pool;  //保存闲置的Connection对象
        
        public DBConnectionPool(String driver,String jdbcUrl) throws ClassNotFoundException
        {
            this.jdbcUrl = jdbcUrl;
            Class.forName(driver);
              pool = new LinkedList<Connection>();
        }
        
        public DBConnectionPool(String driver,String jdbcUrl,String username,String password) throws ClassNotFoundException
        {
           this.jdbcUrl = jdbcUrl;
           this.username = username;
           this.password = password;
           Class.forName(driver);
           pool = new LinkedList<Connection>();
        }
        
    //为了可以在多线程环境下使用,对一些方法使用synchronized关键字同步
    public synchronized Connection getConnection() throws SQLException { Connection conn = null; if(pool.size() > 0) conn = pool.poll(); else { final Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
    //创建代理对象,并强制转换为Connection接口类型,InvocationHandler接口表示调用处理器 conn
    = (Connection)Proxy.newProxyInstance(null,new Class[]{Connection.class},new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName() == "close" && method.getParameterTypes().length == 0) { pool.add((Connection)proxy); //执行close方法时,替换原方法的逻辑 return null; } else //执行其他方法时,保持原方法的逻辑 return method.invoke(connection,args); } }); } return conn; } public synchronized Connection getConnection(String username, String password) throws SQLException { Connection conn = null; if(pool.size() > 0) conn = pool.poll(); else { final Connection connection = DriverManager.getConnection(jdbcUrl, username, password); conn = (Connection)Proxy.newProxyInstance(null,new Class[]{Connection.class},new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName() == "close" && method.getParameterTypes().length == 0) { pool.add((Connection)proxy); return null; } else return method.invoke(connection,args); } }); } return conn; } public synchronized void reduce() throws SQLException { int size = pool.size(); while(pool.size() > (size / 2) ) pool.poll().close(); } public synchronized void close() throws SQLException { while(pool.size() > 0) pool.poll().close(); } }

      

    参考资料 《Java核心技术》

  • 相关阅读:
    【转】Android系统中Fastboot和Recovery所扮演的角色。
    【转】Android ROM分析(1):刷机原理及方法
    【转】ANDROIDROM制作(一)——ROM结构介绍、精简和内置、一般刷机过程
    【转】使用fastboot命令刷机流程详解
    检测是否安装或者开启flash
    CentOS中/英文环境切换教程(CentOS6.8)
    id: cannot find name for user ID xxx处理办法
    linux重命名所有find查找到的文件/文件夹
    linux过滤旧文件中的空行和注释行剩余内容组成新文件
    CentOS和AIX查看系统序列号
  • 原文地址:https://www.cnblogs.com/jqctop1/p/4760043.html
Copyright © 2011-2022 走看看