zoukankan      html  css  js  c++  java
  • JDBC

      

    连接数据的步骤
    注册驱动 (只做一次)
    建立连接(Connection)
    创建执行SQL的语句(Statement)
    执行语句
    处理执行结果(ResultSet)
    释放资源

    一、工具类

    Class.forName(“com.mysql.jdbc.Driver”);
    推荐这种方式,不会对具体的驱动类产生依赖。
    DriverManager.registerDriver(com.mysql.jdbc.Driver);
    会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
    System.setProperty(“jdbc.drivers”, “driver1:driver2”);
    虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
    驱动类型(四种类型)
     
    Connection conn = DriverManager.getConnection(url, user, password);
    url格式:
    JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&…
    User,password可以用“属性名=属性值”方式告诉数据库;
    其他参数如:useUnicode=true&characterEncoding=GBK。

    public final class JdbcUtils {
     private static String url="jdbc:mysql://localhost:3306/jdbc";
     private static String user="root";
     private static String password="******";
     private JdbcUtils(){
      
     }
     static{
      try {
    //   注册驱动
       Class.forName("com.mysql.jdbc.Driver");//推荐
    //   DriverManager.registerDriver(new com.mysql.jdbc.Driver());//2
    //   System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver[:...:...]");//注册方式3可以注册多个驱动用“:”分隔。
      } catch (ClassNotFoundException e) {
       throw new ExceptionInInitializerError(e);
      }
     }
     public static Connection getConnection() throws SQLException{
      return DriverManager.getConnection(url, user, password);
     }
     public static void free(ResultSet rs,Statement st,Connection conn){
      try {
       if(rs!=null)
        rs.close();
      } catch (SQLException e) {
       e.printStackTrace();
      }finally{
       try {
        if(st!=null)
        st.close();
       } catch (SQLException e) {
        e.printStackTrace();
       }finally{
        try {
         if(conn!=null)
         conn.close();
        } catch (SQLException e) {
         e.printStackTrace();
        }
       }
      }
     }
    }

    二、应用类

    l释放ResultSet, Statement,Connection.
    l数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
     
    Connection conn = null;
    Statement st=null;
    ResultSet rs = null;
    try {
    //获得Connection
    //创建Statement
    //处理查询结果ResultSet
    } finally {
    //释放资源ResultSet, Statement,Connection
    }
     

    public class Base {
     public static void main(String[] args) {
      template();
     }
     static void template(){
      Connection conn=null;
      Statement st=null;
      ResultSet rs=null;
      try {
    //   建立连接
       conn=JdbcUtils.getConnection();
    //   创建语句
       st=conn.createStatement();
    //   执行语句
       rs=st.executeQuery("select * from user");
    //   处理结果
       while(rs.next()){
        System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)
          +"\t"+rs.getObject(3)+"\t"+rs.getObject(4));
       }
      } catch (Exception e) {
       e.printStackTrace();
      }finally{
    //   释放资源
       JdbcUtils.free(rs, st, conn);
      }
     }
    }

    l在SQL中包含特殊字符或SQL的关键字(如:' or 1 or ')时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
    lPreperedStatement(从Statement扩展而来)相对Statement的优点:
    1.没有SQL注入的问题。
    2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
    3.数据库和驱动可以对PreperedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。
      
    l详细信息见java.sql.Types
    l几种特殊且比较常用的类型
    1.DATA,TIME,TIMESTAMPà date,time,datetime
    存:ps.setDate(i,d); ps.setTime(i,t); ps.setTimestamp(i, ts);
        取:rs.getDate(i); rs.getTime(i); rs.getTimestamp(i);
    2.CLOB à text
      存:ps.setCharacterStream(index, reader, length);
             ps.setString(i, s);
      取:reader = rs. getCharacterStream(i);
             reader = rs.getClob(i).getCharacterStream();
             string = rs.getString(i);
    3.BLOB à blob
     存:ps.setBinaryStream(i, inputStream, length);
           取:rs.getBinaryStream(i);
            rs.getBlob(i).getBinaryStream();
      
    JavaEE三层架构简介
    表示层 、业务逻辑层、数据访问层,三层之间用接口隔离。
    定义domain对象User,定义存取用户的接口
    用JDBC实现接口
    用配置文件(properties)和反射实现与具体类的耦合

    三、几个API
    *  PreparedStatement.getGeneratedKeys()
    *  PreparedStatement ps=connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
    *  ps.executeUpdate();
    *  ResultSet rs=st.getGeneratedKeys();
    *  rs.getInt(1);

    可用于判断是否操作成功。

    public class OtherApi {
     public static void main(String[] args) {
      int id=create();
      System.out.println("i="+id);
     }
     static int create(){
      int id=0;
      Connection conn=null;
      PreparedStatement ps=null;
      ResultSet rs=null;
      try {
    //   建立连接
    //   conn=JdbcUtils.getConnection();
       conn=JdbcUtilsSing.getInstance().getConnection();//使用单例
       String sql="insert into user(name,birthday,money)values('name1 gk','1987-01-01',400)";
       ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//插入之后从JDBC驱动将主键返回给程序
       ps.executeUpdate();
       rs=ps.getGeneratedKeys();//返回rs是因为主键可能不同的类型,也可能是复合主键 。
       if(rs.next()){
        id=rs.getInt(1);
       }
       System.out.println("i="+id);
      } catch (Exception e) {
       e.printStackTrace();
      }finally{
    //   释放资源
       JdbcUtils.free(rs, ps, conn);
      }
      return id;
     }
    }

    ---------------------------------------------------------------------------------------------------------------

    *  批处理,可以幅提升大量增、删、改的速度。
    *  PreparedStatement.addBatch();
    *  PreparedStatement.executeBatch();

    public class BatchTest {
     public static void main(String[] args) {
      long start=System.currentTimeMillis();
      /*for(int i=0;i<1000;i++){
       create(i);
      }*/
      createBatch();
      long end=System.currentTimeMillis();
      System.out.println("create:"+(end-start));
     }
     /*static void create(int i){
      int id=0;
      Connection conn=null;
      PreparedStatement ps=null;
      ResultSet rs=null;
      try {
    //   建立连接
    //   conn=JdbcUtils.getConnection();
       conn=JdbcUtilsSing.getInstance().getConnection();//使用单例
       String sql="insert into user(name,birthday,money)values(?,?,?)";
       ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//插入之后从JDBC驱动将主键返回给程序
       ps.setString(1, "batch name"+i);
       ps.setDate(2, new Date(System.currentTimeMillis()));
       ps.setFloat(3, 100f+i);
       ps.executeUpdate();
       rs=ps.getGeneratedKeys();//返回rs是因为主键可能不同的类型,也可能是复合主键 。
       
       if(rs.next()){
        id=rs.getInt(1);
       }
       System.out.println("i="+id);
      } catch (Exception e) {
       e.printStackTrace();
      }finally{
    //   释放资源
       JdbcUtils.free(rs, ps, conn);
      }
    //  return id;
     }*/
     static void createBatch(){
      Connection conn=null;
      PreparedStatement ps=null;
      ResultSet rs=null;
      try {
    //   建立连接
    //   conn=JdbcUtils.getConnection();
       conn=JdbcUtilsSing.getInstance().getConnection();//使用单例
       String sql="insert into user(name,birthday,money)values(?,?,?)";
       ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//插入之后从JDBC驱动将主键返回给程序
       for(int i=0;i<1000;i++){
        ps.setString(1, "batch name"+i);
        ps.setDate(2, new Date(System.currentTimeMillis()));
        ps.setFloat(3, 100f+i);
        ps.addBatch();
       }
       int[] is=ps.executeBatch();
      } catch (Exception e) {
       e.printStackTrace();
      }finally{
    //   释放资源
       JdbcUtils.free(rs, ps, conn);
      }
     }
    }

    -----------------------------------------------------------------------------------------------------------------------------------

    *  可滚动的结果集
    *  Statement st=connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATEBLE);
    *  ResultSet rs=st.executeQuery(sql);
    *  rs.beforeFirst();rs.afterLast();rs.first();rs.isFirst();rs.last();rs.isLast();rs.absolute(9);rs.moveToInsertRow();
    public class ScrollTest {
     public static void main(String[] args) {
      scroll();
     }

     static void scroll() {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;
      try {
       // 建立连接
       // conn=JdbcUtils.getConnection();
       conn = JdbcUtilsSing.getInstance().getConnection();// 使用单例
       String sql = "select id,name,birthday,money from user";
       ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE,
         ResultSet.CONCUR_READ_ONLY);
       rs = ps.executeQuery();
    //   rs.afterLast();//到最后一行的后一行,此时要读到记录必须前移
    //   rs.beforeFirst();//到第一行的前面
    //   boolean b=rs.first();//判断当前是不是第一行
    //   boolean b=rs.last();//判断当前是不是最后一行
       while (rs.next()) {
        // System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"+rs.getObject(3)+"\t"+rs.getObject(4));
        System.out.println(rs.getInt("id") + "\t"
          + rs.getString("name") + "\t" + rs.getDate("birthday")
          + "\t" + rs.getFloat("money"));
       }
       System.out.println("---------------------------------------");
       rs.absolute(5);//定位到第五行,可用于分页,要全部查出再分页,效率低
       int i=0;
       while(rs.previous()&&i++<3) {
        System.out.println(rs.getInt("id") + "\t"
          + rs.getString("name") + "\t" + rs.getDate("birthday")
          + "\t" + rs.getFloat("money"));
       }
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       // 释放资源
       JdbcUtils.free(rs, ps, conn);
      }
     }
    }

    ------------------------------------------------------------------------------------------------------------

    *  可更新的结果集
    *  conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATEBLE);
    *  rs.updateString("col name","new value");
    *  rs.updateRow();

     static void read(){
      Connection conn=null;
      PreparedStatement ps=null;
      ResultSet rs=null;
      try {
    //   建立连接
    //   conn=JdbcUtils.getConnection();
       conn=JdbcUtilsSing.getInstance().getConnection();//使用单例
       String sql="select id,name,birthday,money from user where id>7";
       ps=conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
       rs=ps.executeQuery();
       while(rs.next()){
    //    System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"+rs.getObject(3)+"\t"+rs.getObject(4));
        System.out.println(rs.getInt("id")+"\t"
          +rs.getString("name")+"\t"
          +rs.getDate("birthday")+"\t"
          +rs.getFloat("money"));
        String name=rs.getString("name");
        if("batch name2".equals(name)){
         rs.updateFloat("money", 200f);
         rs.updateRow();
        }
       }
      } catch (Exception e) {
       e.printStackTrace();
      }finally{
    //   释放资源
       JdbcUtils.free(rs, ps, conn);
      }
     }

    四、数据库源信息

    DatabaseMetaData meta = connection.getMetaData();
    通过DatabaseMetaData可以获得数据库相关的信息如:数据库版本、数据库名、数据库厂商信息、是否支持事务、是否支持某种事务隔离级别,是否支持滚动结果集等。

    public class DBMD {
     public static void main(String[] args) throws SQLException {
      Connection conn=JdbcUtils.getConnection();
      DatabaseMetaData dbmd=conn.getMetaData();//返回数据库的源信息
      System.out.println("db name:"+dbmd.getDatabaseProductName());//数据库名
      System.out.println("tx:"+dbmd.supportsTransactions());//是否支持事务
      conn.close();
     }
    }

    ----------------------------------------------------------------------------------------------------------------

    ParameterMetaData pmd = preparedStatement.getParameterMetaData();
    通过 ParameterMetaData可以获得参数信息。

    public class ParameterMetaTest {
     public static void main(String[] args) {
      Object[] params = new Object[] { "lisi",new Date(System.currentTimeMillis()), 100f };
      read("select * from user where name=? and birthday<? and money>?",params);
     }

     static void read(String sql, Object[] params) {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;
      try {
       // 建立连接
       // conn=JdbcUtils.getConnection();
       conn = JdbcUtilsSing.getInstance().getConnection();// 使用单例
       ps = conn.prepareStatement(sql);
       // ParameterMetaData pmd = ps.getParameterMetaData();
       // int count = pmd.getParameterCount();
       // for (int i = 1; i <= count; i++) {
       // ps.setObject(i, params[i - 1]);
       // }
       for (int i = 1; i <= params.length; i++) {
        ps.setObject(i, params[i - 1]);
       }
       // for (int i = 1; i <= count; i++) {
       // System.out.print(pmd.getParameterClassName(i)+"\t");
       // System.out.print(pmd.getParameterType(i)+"\t");
       // System.out.println(pmd.getParameterTypeName(i));
       // }
       rs = ps.executeQuery();
       while (rs.next()) {
        System.out.println(rs.getInt("id") + "\t" + rs.getString("name") + "\t" + rs.getDate("birthday")+ "\t" + rs.getFloat("money"));
       }
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       JdbcUtils.free(rs, ps, conn);
      }
     }
    }

    ----------------------------------------------------------------------------------------------------------------------

    ResultSetMetaData meta = rs.getMetaData();

    通过ResultSetMetaData可以获得结果有几列、各列名、各列别名、各列类型等。
    可以将ResultSet放入Map(key:列名 value:列值)。
    用反射ResultSetMetaData将查询结果读入对象中(简单的O/RMapping)
    1)让SQL语句中列别名和要读入的对象属性名一样;
    2)通过ResultSetMetaData获得结果列数和列别名;
    3)通过反射将对象的所有setXxx方法找到;
    4)将3)找到的方法setXxx和2)找到的列别名进行匹配(即方法中的xxx于列别名相等);
    5)由上一步找到的方法和列别名对应关系进行赋值
    Method.invoke(obj, rs.getObject(columnAliasName));

    public class ResultSetMetaDataTest {
     public static void main(String[] args) {
      List<Map<String,Object>> datas=read("select * from user where id<5");
      System.out.println(datas);
     }
     static List<Map<String, Object>> read(String sql) {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;
      List<Map<String,Object>> datas=null;
      Map<String,Object> data=null;
      try {
       // 建立连接
       // conn=JdbcUtils.getConnection();
       conn = JdbcUtilsSing.getInstance().getConnection();// 使用单例
       ps = conn.prepareStatement(sql);
       rs = ps.executeQuery();
       ResultSetMetaData rsmd = rs.getMetaData();
       int count = rsmd.getColumnCount();
       String[] colNames=new String[count];
        for (int i = 1; i <= count; i++) {
    //    System.out.print(rsmd.getColumnClassName(i) + "\t");
    //    System.out.print(rsmd.getColumnName(i) + "\t");
    //    System.out.println(rsmd.getColumnLabel(i) + "\t");
        colNames[i-1]=rsmd.getColumnLabel(i);//如果设置了别名使用,没有的话Name与Label一样
       }
        datas=new ArrayList<Map<String,Object>>();
       while (rs.next()) {
        data=new HashMap<String,Object>();
        for(int i=0;i<colNames.length;i++){
         data.put(colNames[i], rs.getObject(colNames[i]));
        }
        datas.add(data);
       }
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       JdbcUtils.free(rs, ps, conn);
      }
      return datas;
     }
    }

  • 相关阅读:
    Vue
    多线程
    多进程进阶
    CentOS7中安装MySQL
    socket
    回顾
    Hibernate学习一:Hebinate入门以及一些小问题
    struts2学习二:Tomcat的部署目录和访问路径问题
    struts2学习一:hello struts2及struts2环境配置中遇到的问题
    Scanner几个问题与正则简介
  • 原文地址:https://www.cnblogs.com/mingforyou/p/2281913.html
Copyright © 2011-2022 走看看