时间:2021-07-01 10:21:17 帮助过:5人阅读
DatabaseMetaData 类中提供了许多方法用于获得数据源的各种信息,通过这些方法可以非常详细的了解数据库的信息:
getURL():返回一个String类对象,代表数据库的URL。 getUserName():返回连接当前数据库管理系统的用户名。 isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。 getDatabaseProductName():返回数据库的产品名称。 getDatabaseProductVersion():返回数据库的版本号。 getDriverName():返回驱动驱动程序的名称。 getDriverVersion():返回驱动程序的版本号。
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象:
getColumnName(int column):获取指定列的名称 getColumnCount():返回当前 ResultSet 对象中的列数。 getColumnTypeName(int column):检索指定列的数据库特定的类型名称。 getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。 isNullable(int column):指示指定列中的值是否可以为 null。 isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。
在 ResultSet 中,只有一列 Generated_Key, 用于存放新生成的主键值。
/** * 通用的查询方法:可以根据传入的 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; }
LOB,即Large Objects(大对象),是用来存储大量的二进制和文本数据的一种数据类型(一个LOB字段可存储可多达4GB的数据)。
LOB 分为两种类型:内部LOB和外部LOB。
内部LOB将数据以字节流的形式存储在数据库的内部。因而,内部LOB的许多操作都可以参与事务,也可以像处理普通数据一样对其进行备份和恢复操作。
BLOB(二进制数据)
CLOB(单字节字符数据)
NCLOB(多字节字符数据)。
CLOB和NCLOB类型适用于存储超长的文本数据,BLOB字段适用于存储大量的二进制数据,如图像、视频、音频,文件等。
MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)
插入 BLOB 类型的数据必须使用 PreparedStatement:因为 BLOB 类型的数据时无法使用字符串拼写的。 调用 setBlob(int index, InputStream inputStream)
读取 blob 数据: 1. 使用 getBlob 方法读取到 Blob 对象 2. 调用 Blob 的 getBinaryStream() 方法得到输入流。再使用 IO 操作即可.
保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(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 种事务隔离级别: