利用Connection.preparedStatement()
的重载方法PreparedStatement preparedStatement(String sql, int autoGeneratedKeys) throws SQLException
,该方法创建一个默认的PreparedStatement
对象,该对象具有检索自动生成的键的能力。int autoGeneratedKeys
——指示是否应返回自动生成的键的标志;常量Statement.RETURN_GENERATED_KEYS和Statement.NO_GENERATED_KEYS
表示生成的键可/不可用于检索。该方法获取的主键存放在PreparedStatement
里,通过PreparedStatement.getGeneratedKeys()
方法获取,该方法返回一个ResultSet。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test4 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = new StringBuffer()
.append(" insert into ")
.append(" t_user ")
.append(" (username,password,age) ")
.append(" values ")
.append(" ('zhangsan','123',18) ")
.toString();
try {
conn = JdbcUtil.getConnection();
//传入常量值RETURN_GENERATED_KEYS,表示返回生成的主键
ps = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
ps.executeUpdate();
//获取存储主键的结果集
rs = ps.getGeneratedKeys();
while(rs.next()) {//可能是复合主键
System.out.println(rs.getInt(1));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps);
}
}
}
注:JdbcUtil是数据库工具类,封装了连接数据库和关闭资源的方法,具体可参考我的上一篇博客
Transaction事务是用来保证数据操作的完整性
一个业务由若干个一次性的操作组成,这些操作要么都成功,要么都失败,如银行转账(对应数据库的多个操作,A给B转钱,在数据库底层要对A做一次更新操作,对B做一次更新操作,对业务而言,这两个操作是一个整体,只有两个操作都成功才算业务成功,如果A操作成功,B操作失败,业务就是失败,那就得回滚——撤销)
事务的四大特性ACID
原子性(Atomicity):不可再分
一致性(Consistency):事务执行的前后,数据库是一致的
隔离性(Isolation):两个事务的操作互不干扰
持久性(Durability):事务提交后,结果被永久保存下来
JDBC默认是自动提交事务的,将每一条SQL语句都当作一个独立的事务执行
关闭自动提交事务Connection.setAutoCommit(false);
提交事务Connection.commit()
回滚事务Connection.rollback()
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test05 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
//关闭自动提交事务
conn.setAutoCommit(false);
ps = conn.prepareStatement("insert into t_user values (null,'xxx','111',20)");
ps.executeUpdate();
ps = conn.prepareStatement("insert into t_user values (null,'yyy','111',20)");
ps.executeUpdate();
//提交事务
conn.commit();
System.out.println("同时添加两个用户成功!");
} catch (SQLException e) {
//回滚事务
try {
conn.rollback();
System.out.println("操作被回滚,出现异常:"+e.getMessage());
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
JdbcUtil.close(conn, ps);
}
}
}
当需要执行的SQL语句比较多时,每次发送一条SQL语句并执行的效率很低,此时可以批量处理并执行SQL
实现步骤:
- 在url中添加
rewriteBatchedStatements=true
参数,启用批处理
- 调用addBatch()方法,添加批处理,放到缓冲区
- 设置批处理大小,调用executeBatch(),执行批处理(批处理一次执行多少条需要人为优化)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test05 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
//批处理前一般都关闭自动提交事务,防止出错
conn.setAutoCommit(false);
ps = conn.prepareStatement("insert into t_user values (null,?,?,?)");
for(int i = 0;i < 300000; i++) {//30万条
ps.setString(1, "name" + i);
ps.setString(2, "123");
ps.setInt(3, 18);
//添加批处理,放到缓冲区
ps.addBatch();
//设置批处理大小
if(i % 10000 == 0) {
//执行批处理
ps.executeBatch();
//提交事务
conn.commit();
}
}
//最后一次可能不足一万条,防止数据没被提交,再执行一次
ps.executeBatch();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps);
}
}
}
事务和批处理的区别:
事务:
底层是在数据库方存储SQL,没有提交事务的数据放在数据库的临时表空间
最后一次把临时表空间中的数据提交到数据库服务器执行
消耗的数据库服务器内存
批处理:
底层是在客户端存储SQL
最后一次把客户端存储的数据发送到数据库服务器执行
消耗的是客户端的内存
MetaData元数据是用来描述数据的数据,主要是描述数据属性的信息
分类:
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
public class Test05 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
/*
* 获取数据库元数据
*/
DatabaseMetaData dbmd = conn.getMetaData();
System.out.println(dbmd.getDatabaseProductName());//获取数据库产品名
System.out.println(dbmd.getDatabaseProductVersion());//获取数据库产品版本
System.out.println(dbmd.getDriverName());//获取数据库驱动名
System.out.println(dbmd.getDriverVersion());//获取数据库驱动版本
System.out.println(dbmd.getUserName());//获取数据库用户名
ps = conn.prepareStatement("select * from t_user");
rs = ps.executeQuery();
/*
* 获取结果集元数据
*/
ResultSetMetaData rsmd = rs.getMetaData();
System.out.println("总列数:" + rsmd.getColumnCount());//获取结果集的总列数
for(int i = 1; i <= rsmd.getColumnCount(); i++) {
System.out.println(rsmd.getColumnName(i)+"\t"+rsmd.getColumnTypeName(i));//获取列名和列的类型
System.out.println(rsmd.getTableName(i));//获取该列所属的表名
System.out.println(rsmd.isAutoIncrement(i));//获取该列是否自动增长
System.out.println(rsmd.isNullable(i));//获取该列能否为空,0表示为not null,1表示可为null
System.out.println("-------------");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps);
}
}
}