菜鸟学JDBC(二)

摘要:
优化内容如下:1。优化数据库关闭部分;2.优化查询过程=Null)//否则可能引发空指针异常rs.close();rs=空;}Catch{e.printStackTrace();}finally{try{if(stat!=null){synchronized//获取锁,处理并发操作{如果(sin!=null)stat.close();stat=null;}Catch{//TODO自动生成的Catch块e.printStack Trace(();{finally}try{if(conn!
 
上一篇文章( http://blog.csdn.net/rowandjj/article/details/8883383)我们了解了如何通过JDBC连接mysql数据库,并通过一个简单的代码示例演示了具体的操作,这里简单回顾一下流程:
1.装载驱动(Class.forName()....);
2.通过DriverManager类与数据库建立连接(Connection conn = DriverManager.getConnection()....);
3.创建sql语句(Statement st = conn.createStatement()....);
4.执行sql语句(st.execute(String sql)...);
5.处理查询结果(如果是select等查询语句,会返回一个ResultSet结果集,可以对其进行操作);
相信到这里大家对如何连接数据库已经有了一个初步的了解,下面我们着手对上次的代码进行优化。
优化内容如下:
1.对关闭数据库部分进行优化(异常的处理);
2.对查询流程进行优化(Statement与PreparedStatement)。
3.对架构进行优化(JDBC工具类,封装与数据库连接,注册驱动,关闭连接等重复操作);
我们先来写一个JDBC工具类吧!
注:代码中导入的Connection等类均为java.sql包中的,不要导入mysql包的!
方案一:
package demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public final class JDBCUtils
{
    private JDBCUtils(){}//因为是工具类,所以不需要new对象(因为全部是静态方法)
    
    private static String driverName = "com.mysql.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost/db_test";
    private static String userName = "root";
    private static String password = "sjjhong";
    
//    注册驱动放在静态代码块中,保证只注册一次,当类装载到虚拟机中就会执行----->不用显式调用
    static
    {
        try
        {
            Class.forName(driverName);
        }
        catch (ClassNotFoundException e)
        {
            // TODO 自动生成的 catch 块
            throw new ExceptionInInitializerError();//初始化失败
        }
    }
    public static Connection getConnection() throws SQLException
    {
        //建立连接
        return DriverManager.getConnection(url,userName,password);
    }
    public static void free(ResultSet rs,Statement stat,Connection conn)
    {
        try
        {
            if(rs != null)//否则可能会抛空指针异常
                rs.close();
            rs = null;
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if(stat != null)
                    stat.close();
                stat = null;
            }
            catch (SQLException e)
            {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            finally
            {
                try
                {
                    if(conn != null)
                        conn.close();
                    conn = null;
                }
                catch (SQLException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

在上面工具类中我们封装了一些常用的方法,如装载驱动,建立连接,关闭资源等。因为这些操作出现的频率很高,增删改查等方法中都会涉及这这些操作,经过封装之后,提高了代码的复用性。
另外我们针对关闭数据库资源部分进行了优化,处理了异常,具体大家请参考代码,自己思考为什么这样做。
方案二(用单例写的工具类):
package demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public final class SingDemo
{
    private static String driverName = "com.mysql.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost/db_test";
    private static String userName = "root";
    private static String password = "sjjhong";
    
    private SingDemo(){}
    
    private static SingDemo sin = null;//这里用的是懒加载的模式(最好使用饿汉式,安全方便)
    
    public static SingDemo getInstance()//获取实例
    {
        if(sin != null)
        {
            synchronized (SingDemo.class)//获取锁定,处理并发操作
            {
                if(sin != null)
                {
                    sin = new SingDemo();
                }
            }
        }
        return sin;
    }
    
    static
    {
        try
        {
            Class.forName(driverName);
        }
        catch (ClassNotFoundException e)
        {
            throw new ExceptionInInitializerError();
        }
    }
    public Connection getConnection() throws SQLException
    {
        return DriverManager.getConnection(url,userName,password);
    }
    public void free(ResultSet rs,Statement stat,Connection conn)
    {
        try
        {
            if(rs != null)//否则会抛空指针异常
                rs.close();
            rs = null;
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if(stat != null)
                    stat.close();
                stat = null;
            }
            catch (SQLException e)
            {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            finally
            {
                try
                {
                    if(conn != null)
                        conn.close();
                    conn =null;
                }
                catch (SQLException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

我们继续优化,试想,如果我们更改了数据库或者用户名密码,我们就需要重新更改源代码,很不方便,怎样能解决这个问题呢?我们可以通过配置文件的方式解决!写入配置文件后,我们可以通过修改配置文件直接修改我们要连接的数据库,出错的概率更小。
方案三(将驱动名,url等内容写入配置文件):
package biogDemo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBUtils
{
    private static String driverName = null;
    private static String user = null;
    private static String url = null;
    private static String password = null;
    
    
    private static DBUtils instance = null;
    public static DBUtils getInstance()
    {
        if(instance == null)
        {
            synchronized (DBUtils.class)
            {
                if(instance == null)
                {
                    instance = new DBUtils();
                }
            }
        }
        return instance;
    }
    private DBUtils()
    {
        try
        {
            Properties prop = new Properties();
            prop.load(new FileInputStream(getPropertyFilePath()));//载入配置文件
            
            //读取配置文件并赋值
            driverName = prop.getProperty("driverName");
            user = prop.getProperty("user");
            url = prop.getProperty("url");
            password = prop.getProperty("password");
            
            Class.forName(driverName);
        }
        catch (ClassNotFoundException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        catch (FileNotFoundException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        catch (IOException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    public String getPropertyFilePath()
    {
        StringBuilder sb = new StringBuilder();
        sb.append(System.getProperty("user.dir"));//当前路径
        sb.append("\\src\\").append("biogDemo\\").append("db.properties");
        return sb.toString();
    }
    public Connection getConnection() throws SQLException
    {
        return DriverManager.getConnection(url, user, password);
    }
    public static void free(Connection conn,Statement stat,ResultSet rs)
    {
        try
        {
            if(rs != null)
            {
                rs.close();
            }
            rs = null;
        }
        catch (SQLException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if(stat != null)
                {
                    stat.close();
                }
                stat = null;
            }
            catch (SQLException e)
            {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            finally
            {
                try
                {
                    if(conn != null)
                    {
                        conn.close();
                    }
                    conn = null;
                }
                catch (SQLException e)
                {
                    e.printStackTrace();
                }
                
            }
        }
    }
} 

其中,db.properties文件中写入如下内容:
driverName = com.mysql.jdbc.Driver
password = sjjhong
url = jdbc:mysql://localhost/test
user = root 

好,本次优化就到这里,这还远远不够,后面的博文会进一步完善(结合连接池等...)
下面我们简单使用一下我们的工具类吧!(使用方案一)
package biogDemo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import demo.JDBCUtils;
/**
 * @author Rowand jj
 *
 */
public class Main
{
    public static void main(String[] args)
    {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        
        String sql = "select id,name,birthday,money from tb_9 where id> ?";
        int ID = 2;
        try
        {
            conn = JDBCUtils.getConnection();//建立连接
            ps = conn.prepareStatement(sql);
            ps.setInt(1,ID);//设置sql语句中的通配符(?)为ID
            
            //ResultSetMetaData可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
            ResultSetMetaData rsmd = ps.getMetaData();
            int COUNT = rsmd.getColumnCount();//获取列数
            rs = ps.executeQuery();            //执行查询
            while(rs.next())
            {
                for(int i = 1;i <= COUNT;i++)
                {
                    System.out.print(rs.getObject(i) + " ");
                }
                System.out.println("\n");
            }
            
        }
        catch(SQLException e)
        {
            throw new RuntimeException("查询失败!");
        }
        finally
        {
//            释放,你懂得。别忘了!
            JDBCUtils.free(rs, ps, conn);
        }
    }
} 

我们注意到上面的例子中,我们并没有使用Statement而是改成了PreparedStatement,那么这个类和Statement有什么区别呢?
我们先来看一下文档对PreparedStatement的描述吧!
菜鸟学JDBC(二)第1张
 
 
可以看到,PreparedStatement继承了Statement,而且功能更强大!最明显的就是处理查询语句的灵活性,可以用?代替查询条件,并提供一系列的set方法替换?。
区别:
Statement:(用于执行不带参数的简单 SQL 语句)
每次执行sql语句, 数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。

PreparedStatement:(用于执行带或不带 IN 参数的预编译 SQL 语句)
1.执行的SQL语句中是可以带参数的,并支持批量执行SQL。由于采用Cache机制,则预先编译的语句,就会放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,故相同操作批量数据效率较高。
2.相对较安全,可以防止sql注入
 
这里强烈建议大家使用PreparedStatement。
 
好了,本文到此为止,下一篇我们将介绍基本的增删改查操作以及对不同数据类型的处理!敬请期待。
 

免责声明:文章转载自《菜鸟学JDBC(二)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】Win7注册表的使用(更新中)VMWare虚拟机网络的三种工作模式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java并发编程之异步Future机制的原理和实现

项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable看下面的代码: Java代码   import java.util.concurrent.Callable;   import java.util.concurrent.Execut...

服务器压力上不去原因分析

百兆的带宽在理论上1秒钟可以传输12.5MB的数据,但是考虑到干扰因素每秒传输只要超过10MB就比较正常啦。千兆带宽每秒传输是100M。 http://www.cnblogs.com/candle806/archive/2011/04/02/2003828.html 通过分析,处于峰值只有网络带宽,为90%以上,而对比此处的吞吐率值恰为95MB/s左右,1...

.net 分布式架构之分布式锁实现

分布式锁 经常用于在解决分布式环境下的业务一致性和协调分布式环境。 实际业务场景中,比如说解决并发一瞬间的重复下单,重复确认收货,重复发现金券等。 使用分布式锁的场景一般不能太多。 开源地址:http://git.oschina.net/chejiangyi/XXF.BaseService.DistributedLock 开源相关群: .net 开源基础服...

JAVA基础4---序列化和反序列化深入整理(JDK序列化)

一、什么是序列化和反序列化? 序列化:将对象状态信息转化成可以存储或传输的形式的过程(Java中就是将对象转化成字节序列的过程) 反序列化:从存储文件中恢复对象的过程(Java中就是通过字节序列转化成对象的过程) 二、为什么要序列化和反序列化? Java中对象都是存储在内存中,准确地说是JVM的堆或栈内存中,可以各个线程之间进行对象传输,但是无法在进程之间...

DBeaver连接达梦数据库

1、连接类型选择ODBC。 2、编辑驱动设置:   1)Class Name:dm.jdbc.driver.DmDriver   2)URL Template:jdbc:dm://{dbserver}/{database}。例如:jdbc:dm://192.168.101.222/UFFICE   3)Default Port:{dbport}   4)L...

ResultSet用法集锦 (转)

转:http://soft-development.iteye.com/blog/1420323 结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等.      结果集读取数据的方法主要是getXXX(),他的参数可以是整型表...