zoukankan      html  css  js  c++  java
  • 菜鸟学JDBC(二)

     
    上一篇文章( 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的描述吧!
     
     
    可以看到,PreparedStatement继承了Statement,而且功能更强大!最明显的就是处理查询语句的灵活性,可以用?代替查询条件,并提供一系列的set方法替换?。
    区别:
    Statement:(用于执行不带参数的简单 SQL 语句)
    每次执行sql语句, 数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。

    PreparedStatement:(用于执行带或不带 IN 参数的预编译 SQL 语句)
    1.执行的SQL语句中是可以带参数的,并支持批量执行SQL。由于采用Cache机制,则预先编译的语句,就会放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,故相同操作批量数据效率较高。
    2.相对较安全,可以防止sql注入
     
    这里强烈建议大家使用PreparedStatement。
     
    好了,本文到此为止,下一篇我们将介绍基本的增删改查操作以及对不同数据类型的处理!敬请期待。
     
  • 相关阅读:
    hdu 1009 贪心算法
    hdu10007
    HDU1005 数列找规律
    HDU1004 (数组元素出现最多)
    HDU1003 dp 动态规划解析
    活字格Web应用平台学习笔记4
    活字格学习
    活字格Web应用平台学习笔记3-显示数据列表
    活字格Web应用平台学习笔记2-基础教程-开始
    活字格Web应用平台学习笔记1
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3074777.html
Copyright © 2011-2022 走看看