JDBC 元数据 事务处理

使用 JDBC 驱动程序处理元数据

  Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面的信息。根据这些信息,JDBC可以访问一个实现事先并不了解的数据库。

  获取这些信息的方法都是在DatabaseMetaData类的对象上实现的,而DataBaseMetaData对象是在Connection对象上获得的

DatabaseMetaData类

  DatabaseMetaData 类中提供了许多方法用于获得数据源的各种信息,通过这些方法可以非常详细的了解数据库的信息:

getURL():返回一个String类对象,代表数据库的URL。
getUserName():返回连接当前数据库管理系统的用户名。
isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
getDatabaseProductName():返回数据库的产品名称。
getDatabaseProductVersion():返回数据库的版本号。
getDriverName():返回驱动驱动程序的名称。
getDriverVersion():返回驱动程序的版本号。

 ResultSetMetaData 类

  可用于获取关于 ResultSet 对象中列的类型和属性信息的对象:

getColumnName(int column):获取指定列的名称
getColumnCount():返回当前 ResultSet 对象中的列数。
getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
isNullable(int column):指示指定列中的值是否可以为 null。
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

 取得数据库自动生成的主键

    

  在 ResultSet 中,只有一列 Generated_Key, 用于存放新生成的主键值。

利用反射及JDBC元数据编写通用的查询方法

/**
	 * 通用的查询方法:可以根据传入的 SQL、Class 对象返回 SQL 对应的记录的对象
	 * @param clazz: 描述对象的类型
	 * @param sql: SQL 语句。可能带占位符
	 * @param args: 填充占位符的可变参数。
	 * @return
	 */
	public <T> T get(Class<T> clazz, String sql, Object... args) {
		T entity = null;

		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;

		try {
			//1. 得到 ResultSet 对象
			connection = JDBCTools.getConnection();
			preparedStatement = connection.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
				preparedStatement.setObject(i + 1, args[i]);
			}
			resultSet = preparedStatement.executeQuery();

			//2. 得到 ResultSetMetaData 对象
			ResultSetMetaData rsmd = resultSet.getMetaData();
			
			//3. 创建一个 Map<String, Object> 对象, 键: SQL 查询的列的别名, 
			//值: 列的值
			Map<String, Object> values = new HashMap<>();
			
			//4. 处理结果集. 利用 ResultSetMetaData 填充 3 对应的 Map 对象
			if(resultSet.next()){
				for(int i = 0; i < rsmd.getColumnCount(); i++){
					String columnLabel = rsmd.getColumnLabel(i + 1);
					Object columnValue = resultSet.getObject(i + 1);
					
					values.put(columnLabel, columnValue);
				}
			}
			
			//5. 若 Map 不为空集, 利用反射创建 clazz 对应的对象
			if(values.size() > 0){
				entity = clazz.newInstance();
				
				//5. 遍历 Map 对象, 利用反射为 Class 对象的对应的属性赋值. 
				for(Map.Entry<String, Object> entry: values.entrySet()){
					String fieldName = entry.getKey();
					Object value = entry.getValue();
					BeanUtils.setProperty(entity, fieldName, value);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCTools.releaseDB(resultSet, preparedStatement, connection);
		}
		return entity;
	}

 Oracle LOB

  LOB,即Large Objects(大对象),是用来存储大量的二进制和文本数据的一种数据类型(一个LOB字段可存储可多达4GB的数据)。

  LOB 分为两种类型:内部LOB和外部LOB。

    内部LOB将数据以字节流的形式存储在数据库的内部。因而,内部LOB的许多操作都可以参与事务,也可以像处理普通数据一样对其进行备份和恢复操作。

      BLOB(二进制数据) 

      CLOB(单字节字符数据)

      NCLOB(多字节字符数据)。

    CLOB和NCLOB类型适用于存储超长的文本数据,BLOB字段适用于存储大量的二进制数据,如图像、视频、音频,文件等。

MySQL BLOB 类型介绍

  MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

  MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

    

  插入 BLOB 类型的数据必须使用 PreparedStatement:因为 BLOB 类型的数据时无法使用字符串拼写的。 调用 setBlob(int index, InputStream inputStream)

  读取 blob 数据: 1. 使用 getBlob 方法读取到 Blob 对象   2. 调用 Blob 的 getBinaryStream() 方法得到输入流。再使用 IO 操作即可.

JDBC 事务处理

  保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态

  为了让多个 SQL 语句作为一个事务执行:

    调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
    在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
    在出现异常时,调用 rollback(); 方法回滚事务
    若此时 Connection 没有被关闭, 则需要恢复其自动提交状态

		try {
			// 开始事务: 取消默认提交. connection.setAutoCommit(false);
			// ...
			// 提交事务 connection.commit();
		} catch (Exception e) {
			// ...
			// 回滚事务
			try {
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			JDBCTools.releaseDB(null, null, connection);
		}

 数据库的隔离级别

  对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:

    脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.

    不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.

    幻读: 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.

  数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.

  一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱

数据库提供的 4 种事务隔离级别:

  

  Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED

  Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ

在 MySql 中设置隔离级别

  每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别.

  查看当前的隔离级别: SELECT @@tx_isolation;

  设置当前 mySQL 连接的隔离级别:   set  transaction isolation level read committed;

  设置数据库系统的全局的隔离级别:   set global transaction isolation level read committed;

批量处理JDBC语句提高处理速度

  当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。

  JDBC的批量处理语句包括下面两个方法:

    addBatch(String):添加需要批量处理的SQL语句或是参数;
    executeBatch();执行批量处理语句;

			for(int i = 0; i < 100000; i++){
				preparedStatement.setInt(1, i + 1);
				preparedStatement.setString(2, "name_" + i);
				
				//"积攒" SQL 
				preparedStatement.addBatch();
				
				//当 "积攒" 到一定程度, 就统一的执行一次. 并且清空先前 "积攒" 的 SQL
				if((i + 1) % 300 == 0){
					preparedStatement.executeBatch();
					preparedStatement.clearBatch();
				}
			}		
			//若总条数不是批量数值的整数倍, 则还需要再额外的执行一次. 
			if(100000 % 300 != 0){
				preparedStatement.executeBatch();
				preparedStatement.clearBatch();
			}

 

DAO 设计模式

what: DAO: data Access Object 。 访问信息数据的类。包含了对数据的增删改查,而不包含任何业务相关信息。

why: 能实现功能的模块化,更有利于代码的维护和升级。

Java 类的属性

  1). 在JavaEE 中,Java类的属性通过getter,setter来定义,除去get 或set 后,第一个字母小写即为Java类的属性。

  2). 以前叫的属性为 成员变量,称之为字段。 一般情况下,字段名和属性名都一致。

  3). 操作Java属性有一个工具包:beanutils

    <1>. 搭建环境:需要同时加入 commons-logging-1.1.1.jar 和 commons-beanutils-1.8.0.jar。

    <2>. setProperty() 和 getProperty() 方法。 

BeanUtils.setProperty(object, "type", 4);
Object type = BeanUtils.getProperty(object, "type");

 

posted @ 2016-06-22 21:31  岳灵珊  阅读(256)  评论(0编辑  收藏  举报