jdbc基础知识(三)

一、简介

  • JDBC(Java Data Base Connectivity,java数据库连接),由一些接口和类构成的API。
  • J2SE的一部分,由java.sql,javax.sql包组成。
  • 应用程序、JDBC API、数据库驱动及数据库之间的关系
    这里写图片描述

连接数据库的步骤:

  • 注册驱动(只需一次)
  • 建立连接(Connection)
  • 创建可执行SQL语句(Statement)
  • 执行语句
  • 处理执行结果(ResultSet)
  • 释放资源

注册驱动的几种方法:

  • Class.forName(com.mysql.jdbc.Driver); 不会对具体的驱动产生依赖
  • DriverManager.registerDriver(com.mysql.jdbc.Driver);会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
  • System.setProperty(“jdbc.drivers”, “driver1:driver2”);虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
    建立连接
    Connecttion conn=DriverManger.getConnection(url,user,password);
  • URL格式:
    jdbc:子协议:子名称//主机名:端口/数据库?属性名=属性值&…
  • User,password可以用“属性名=属性值”方式告诉数据库;
  • 其他参数如:useUnicode=true&characterEncoding=GBK。
    创建执行的SQL语句
  • Statement
Statement st=conn.creatStatement();
 st.executeQuery(sql);
  • PreparedStatemnet
String sql=select * from table_name where col_name =?;
PreparedStatement ps=conn.preparedStatement(sql);
ps.setString(1,"col_value");
ps.executeQuery();

处理执行结果

ResultSet rs=statement.executeQuery(sql);
while(rs.next()){
    rs.getString("col_name");
    rs.getInt(l_name");
    //...}

释放资源

  • 释放ResultSet, Statement,Connection.

  • 数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

    基本的CRUD(创建、读取、更新、删除)

模板代码

Connection conn = null;
Statement st=null;
ResultSet rs = null;
try {
    //获得Connection
    //创建Statement
    //处理查询结果ResultSet
} finally {
    //释放资源ResultSet, Statement,Connection
}

创建
增加对应SQL的INSERT,返回增加成功的行(记录)数

conn=getConnection();
Statement st=conn.createStatement();
String sql="insert into user(name,age,regist_date)"+"values('name',10,now());
int i=st.executeUpdate(sql);
//i为插入的记录数

读取
读取对应sql的select,返回查询结果

conn=getConnection();
st=conn.createStatement();
String sql="select id,name,regist_date from user ";
ResultSet rs=st.executeQuery(sql);
while (rs.next()) {
        System.out.print(rs.getInt("id") + " \t\t ");
        System.out.print(rs.getString("name") + " \t\t ");
        System.out.print(rs.getInt("age") + " \t\t ");
        System.out.print(rs.getTimestamp("regist_date") + " \t\t ");
        System.out.println();
}

更新
更新(修改)对应SQL的UPDATE,返回被修改的行(记录)数

conn = getConnection();
Statement st = conn.createStatement();
String sql=“update person set name='new name‘”;
int i = st.executeUpdate(sql);
//i为符合条件的记录数

删除
删除对应SQL的DELETE,返回被删除的行(记录)数

conn = getConnection();
Statement st = conn.createStatement();
String sql=“delete from user where id=1”;
int i = st.executeUpdate(sql);
//i为删掉的记录数

增删改查总结

  • 增删改用Statement.executeUpdate(sql)来完成,返回整数(匹配的记录数)
  • 查使用Statement.executeQuery(sql);来完成返回的是ResultSet对象,ResultSet中包含了查询的结果;查询相对与增、删、改要复杂一些,因为有查询结果要处理。
    SQL注入,PreparedStatement和Statement
  • 在SQL中包含特殊字符或SQL的关键字(如:’ or 1 or
    ‘)时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。

PreperedStatement(从Statement扩展而来)相对Statement的优点:

  • 1.没有SQL注入的问题。
  • 2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
  • 3.数据库和驱动可以对PreperedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。
    数据类型
  • 详细信息见java.sql.Types
  • 几种特殊且比较常用的类型
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(); 

一个简单用户相关的数据访问层

  • J2EE三层架构简介 表示层 、业务逻辑层、数据访问层,三层之间用接口隔离。
  • 定义domain对象User,定义存取用户的接口
  • 用JDBC实现接口
  • 用配置文件(properties)和反射实现与具体类的耦合
    事务(ACID)
  • 原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分
  • 一致性(consistency):在事务处理执行前后,数据库是一致的(两个账户要么都变,或者都不变)。
  • 隔离性(isolcation):一个事务处理对另一个事务处理没有影响。
  • 持续性(durability):事务处理的效果能够被永久保存下来 。
  • connection.setAutoCommit(false);//打开事务。
  • connection.commit();//提交事务。
  • connection.rollback();//回滚事务。

隔离级别多线程并发读取数据时的正确性

  • connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
  • V:可能出现,X:不会出现

隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted) V V V
读已提交(Read committed) x V V
可重复读(Repeatable read) x x V
可串行化(Serializable ) x x x
存储过程
存储过程

CallableStatement(从PreperedStatement扩展来)
cs = connection.prepareCall(“{call psname(?,?,?)}”);
cs.registerOutParameter(index, Types.INTEGER);
cs.setXXX(i, xxxx);
cs.executeUpdate();
int id=cs.getInt(index);

其他的几个API

Statement.getGeneratedKeys()
    PreparedStatement ps = connection.prepareStatement(sql,     Statement.RETURN_GENERATED_KEYS);
    ps.executeUpdate();
    ResultSet rs = st.getGeneratedKeys();rs.getInt(1);
批处理,可以大幅度提升大量增、删、改的速度。
    PreparedStatement.addBatch();
    PreparedStatement.executeBatch();
可滚动的结果集
    Statement st = 
    connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,     ResultSet.CONCUR_UPDATABLE);
    ResultSet rs = st.executeQuery(sql);
    rs.beforeFirst(); rs.afterLast();rs.first();rs.isFirst();rs.last();rs.isLast();
    rs.absolute(9);rs.moveToInsertRow();

DatabaseMetaData

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

数据源和连接池

  • DataSource用来取代DriverManager来获取Connection;
  • 通过DataSource获得Connection速度很快;
  • 通过DataSource获得的Connection都是已经被包裹过的(不是驱动原来的连接),他的close方法已经被修改。
  • 一般DataSource内部会用一个连接池来缓存Connection,这样可以大幅度提高数据库的访问速度;
  • 连接池可以理解成一个能够存放Connection的Collection;
  • 我们的程序只和DataSource打交道,不会直接访问连接池;
    一个简单的数据源实现
    使用装饰模式的Connection(核心代码)
class MyConnection implements Connection{
        private Connection realConn;
        private LinkedList connPool;
        MyConnection(Connection rConn, LinkedList cPool){
            this.realConn=rConn;
            this.connPool=cPool;
        }
        public void close(){
            this.connPool.addLast(this);
        }

DataSource(核心代码)

class MyDataSource implements DataSource{
        private LinkedList connPool = new Vector();
        public Connection getConneciton (){
            if(this.connPool.size()>0)
                return this.connPool.removeFirst(0);
            return createConnection();
        }
        private Connection createConnection(){
          Connection realConn = DriverManager.getConnection();
          Connection myConn = 
            new MyConnection(realConn,this.connPool);
          return myConn;
        }
        //….
    }

常用的开源实现DBCP

使用DBCP必须用的三个包:
    commons-dbcp-1.2.1.jar, commons-pool-1.2.jar, commons-collections-3.1.jar。
Java API: BasicDataSourceFactory.createDataSource(
properties); 

具体实践

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class Base {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        template(); 

    }

    static void template() throws Exception {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 2.建立连接
            conn = JdbcUtils.getConnection();
            // conn = JdbcUtilsSing.getInstance().getConnection();
            // 3.创建语句
            st = conn.createStatement();

            // 4.执行语句
            rs = st.executeQuery("select * from user");

            // 5.处理结果
            while (rs.next()) {
                // 参数中的1,2,3,4是指sql中的列索引
                System.out.println(rs.getObject(1) + "\t" + rs.getObject(2)
                        + "\t" + rs.getObject(3) + "\t" + rs.getObject(4));
            }
        } finally {
            JdbcUtils.free(rs, st, conn);
        }

    }

    static void test() throws SQLException, ClassNotFoundException {
        // 1.注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");
        Class.forName("com.mysql.jdbc.Driver");// 推荐方式

        // 2.建立连接
        String url = "jdbc:mysql://localhost:3306/jdbc";
        String user = "root";
        String password = "";
        Connection conn = DriverManager.getConnection(url, user, password);

        // 3.创建语句
        Statement st = conn.createStatement();

        // 4.执行语句
        ResultSet rs = st.executeQuery("select * from user");

        // 5.处理结果
        while (rs.next()) {
            System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t"
                    + rs.getObject(3) + "\t" + rs.getObject(4));
        }

        // 6.释放资源
        rs.close();
        st.close();
        conn.close();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值