JDBC知识点

jdbc说明

什么是jdbc?(Java Data Base Connectivity,java数据库连接),由一些接口和类构成的API

步骤

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

注册驱动

  • Class.forName(“com.mysql.jdbc.Driver”); 推荐这种方式,不会对具体的驱动类产生依赖。
  • DriverManager.registerDriver(com.mysql.jdbc.Driver); 会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
  • System.setProperty(“jdbc.drivers”, “driver1:driver2”); 虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
  • 驱动类型(四种类型)

建立连接(Connection)

  • Connection conn = DriverManager.getConnection(url, user, password);
  • url格式: JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&…
  • User,password可以用“属性名=属性值”方式告诉数据库;
  • 其他参数如:useUnicode=true&characterEncoding=GBK。

创建执行SQL的语句(Statement)

  • Statement
	 Statement st = conn.createStatement();
	st.executeQuery(sql);
  • PreparedStatement
	String sql = select * from table_name where col_name=?;
	PreparedStatement ps = conn.preparedStatement(sql);
	ps.setString(1, col_value);
	ps.executeQuery();

处理执行结果(ResultSet)

ResultSet rs = statement.executeQuery(sql);
While(rs.next()){
	rs.getString(col_name);
	rs.getInt(col_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, age,regist_date from user";
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为删掉的记录数

SQL注入,PreparedStatement和Statement

  • 在SQL中包含特殊字符或SQL的关键字(如:' or 1 or ')时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
  • PreperedStatement(从Statement扩展而来)相对Statement的优点: 1.没有SQL注入的问题。 2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。 3.数据库和驱动可以对PreperedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。

数据类型

  • 详细信息见java.sql.Types

  • 几种特殊且比较常用的类型

    • 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);

    • CLOB  text

      存:ps.setCharacterStream(index, reader, length); ps.setString(i, s);

      取:reader = rs. getCharacterStream(i); reader = rs.getClob(i).getCharacterStream(); string = rs.getString(i);

    • BLOB  blob

      存:ps.setBinaryStream(i, inputStream, length);

      取:rs.getBinaryStream(i); rs.getBlob(i).getBinaryStream();

事务(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打交道,不会直接访问连接池;


最后

作者:ricky

交流群: 244930845


猜你喜欢

转载自blog.csdn.net/u014042066/article/details/78872696
今日推荐