事务ACID
原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。
一致性(consistency):在事务处理执行前后,数据库是一致的(两个账户要么都变,或者都不变)。
隔离性(isolcation):一个事务处理对另一个事务处理没有影响。
持续性(durability):事务处理的效果能够被永久保存下来 。
常用API
Connection.setAutoCommit(false): 关闭自动提交,打开事务。
Connection.commit(): 提交事务。
Connection.rollback(): 回滚事务。
Savepoint sp=conn.setSavepoint(): 设置保存点。
Conn.rollback(sp):回滚到保存点。
Conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
设置隔离级别、可以通过Connection中得常量设置。
隔离级别
在多线程并发访问数据库并且使用事务的时候, 可能会遇到脏读, 不可重复读, 幻读的情况, 需要设置隔离级别来避免。
脏读: 读到的线程未提交的数据。
不可重复读: 在一个事务中读取同一个记录两次, 获取数据不同。
幻读: 在一个事务中, 读取到的记录数不同。
select @@tx_isolation: 查看隔离级别
set transaction isolation level read uncommitted: 设置读未提交
set transaction isolation level read committed: 设置读已提交
set transaction isolation level repeatable read: 设置可重复读
set transaction isolation level serializable: 设置可序列化
start transaction: 开始事务
rollback: 回滚事务
commit: 提交事务
获取插入的ID
conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = ps.getGeneratedKeys();
if (rs.next())
user.setId(rs.getInt(1));
MySQL的select last_insert_id()可以获取之前插入的记录的id, 但这只是MySQL才有的函数
只有对自增长的列发生自增长的赋值后才会导致一个key的产生,并且用getGereratedKeys()返回。
批处理
由于建立连接, 以及发送数据非常消耗性能, 如果有大批SQL命令需要处理, 最好使用批处理
ps = conn.prepareStatement("insert into user(name,password,email,birthday) values(?,?,?,?)");
for (User user : list) {
ps.setString(1, user.getName());
ps.setString(2, user.getPassword());
ps.setString(3, user.getEmail());
ps.setDate(4, new Date(user.getBirthday().getTime()));
ps.addBatch();
}
ps.executeBatch();
分页
通过ResultSet的滚动可以设置获取记录的位置, 但这样是从数据库中查询出所有数据, 然后再从结果中筛选结果, 性能非常低。
MySQL提供了分页语法. 在查询语句后可使用LIMIT关键字完成分页功能, 例如:
select * from user limit 40,20
查询从user表中取出从第41条开始的20条记录. 第一个参数表示忽略前面多少个, 第二个参数代表取多少个.
可更新结果集、敏感结果集
conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet.TYPE_SCROLL_SENSITIVE
表示获得ResultSet之后是敏感的, 随数据库更新的. 但MySQL没有支持这项功能
ResultSet.CONCUR_UPDATABLE
表示获得ResultSet之后是可更新的, 例如:
rs.next();
rs.updateString("name", "updateName");
rs.updateRow();
可以将当前行的name属性改为updateName.
元信息数据库元信息
由于每种数据库对JDBC的实现都有所不同, 我们在使用的时候想要了解哪些数据库支持哪些功能, 就可以查看元信息
DatabaseMetaData data = conn.getMetaData():数据库元信息
data.getDatabaseProductName():数据库名
data.getDatabaseProductVersion():数据库版本号
data.getDriverName():驱动名
data.getDriverVersion():驱动版本号
data.supportsTransactions():是否支持事务
data.getDefaultTransactionIsolation():默认事务隔离级别
data.supportsTransactionIsolationLevel(0):是否支持指定的事务隔离级别
data.supportsGetGeneratedKeys():是否支持获取主键
data.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE):是否支持敏感结果集
1.1. 结果集元信息
我们可以根据结果集元信息来写一些灵活性很高的代码. 让代码的复用性更高.
ResultSetMetaData rsmd = ps.getMetaData():获取结果集元信息
rsmd.getColumnCount():获取结果集中包含几列
rsmd.getColumnName(1):获取指定列的名字
rsmd.getColumnLabel(1):获取指定列的别名
rsmd.getColumnClassName(1):获取指定列的Java类型
rsmd.getColumnTypeName(1):获取指定列的数据库类型
反射基础
构造函数
Class.getConstructors():获取所有构造函数
Class.getConstructor(Class...):获取到class中带有指定类型参数的构造函数
Constructor.newInstance(Object...):使用构造函数创建对象, 传入指定参数
方法
Class.getMethods():获取所有公有方法, 包括继承的
Class.getDeclaredMethods():获取所有类中定义的方法, 包括私有的
Class.getMethod(String, Class...):获取指定方法名和参数类型的方法(公有的)
Class.getDeclaredMethod(String, Class...):获取指定方法名和参数类型的方法(类中定义的)
Method.invoke(Object, Object...):在制定对象上运行方法, 将制定参数传入
属性
Class.getFields():获取所有公有属性(包括父类继承的)
Class.getDeclaredFields():获取所有定义的属性(包括私有的)
Class.getField(String):获取指定属性(公有属性)
Class.getDeclaredField(String):获取指定属性(定义属性)
Field.set(Object, Object):设置指定对象的属性值
Field.get(Object):获取指定对象的属性值
Filed.setAccessible(Boolean):设置访问权限