JDBC小结
JDBC的性能最大的增进是减少JDBC驱动与数据库之间的网络通讯次数
Util.java(获取连接器)
public Connection getConnection(){
Connection connection=null;
try {
//加载数据库连接驱动
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true";
String user="root";
String password="HengTian0.0";
connection= DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
Statement与PreparedStatement
-
关系:PreparedStatement继承Statement接口,且它们都是接口
-
区别:
-
Statement用来执行静态sql语句,同时同一时间一个Statement只能打开一个ResultSet对象,当只执行一次性sql语句的时候,开销比PreparedStatement小
-
PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程
-
传递给PreparedStatement对象的参数可以被强制进行类型转换,使开发人员可以确保在插入或查询数据时与底层的数据库格式匹配。
-
无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。
-
PrepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。 Statement不会初始化,没有预处理,没次都是从0开始执行SQL
-
PrepareStatement可以使用占位符"?",如:insert into table demo(name,id) values(?,?);
-
PrepareStatement可以用addBatch()方法将将要处理的语句预存起来
例一:
PreparedStatement ps = conn.prepareStatement( "INSERT into employees values (?, ?, ?)"); for (n = 0; n < 100; n++) { ps.setString(name[n]); ps.setLong(id[n]); ps.setInt(salary[n]); ps.executeUpdate(); }
例二:
PreparedStatement ps = conn.prepareStatement( "INSERT into employees values (?, ?, ?)"); for (n = 0; n < 100; n++) { ps.setString(name[n]); ps.setLong(id[n]); ps.setInt(salary[n]); ps.addBatch(); } ps.executeBatch();
在例 1中, PreparedStatement被用来多次执行INSERT语句. 在这里, 执行了100次INSERT操作, 共有101次网络往返.
其中,1次往返是预储PreparedStatement, 另外100次往返执行每个迭代.
在例2中, 当在100次INSERT操作中使用addBatch()方法时, 只有两次网络往返.
1次往返是预储PreparedStatement, 另一次是执行batch命令. 虽然Batch命令会用到更多的数据库的CPU周期, 但是通过减少网络往返,性能得到提高.记住, JDBC的性能最大的增进是减少JDBC驱动与数据库之间的网络通讯.次数
!使用批处理时要在url后面加rewriteBatchedStatements=true表示批量插入,如果不添加的话即使使用addbatch() ,executeBatch() 在后台入库的地方还是不会一次请求入库而是多次请求入库
//批量处理时最好取消自动提交,进行手动提交 connection.setAutoCommit(false);
批量添加的实例
public static void insertData(List<Map<String,String>> list,Logger log){ //获取的数据 List <Map<String,String>> nlist= list; String upsql="update hrd_staff set position =? where id=?"; Iterator<Map<String,String>> iter= nlist.iterator(); Connection con= Utils.getCon(); int count=0; try { //在批量添加的时候注意事务提交方式 con.setAutoCommit(false); //PreparedStatement方法的使用 PreparedStatement pstm = con.prepareStatement(upsql); while(iter.hasNext()){ count++; Map<String,String> map= iter.next(); String jon_name= map.get("job_name"); String uid= map.get("uid"); pstm.setString(1,jon_name); pstm.setString(2,uid); //添加到缓存中 pstm.addBatch(); // 如果数据量很大,不能一次性批量添加所以我们要分批次添加,这里就是300条一次 if(count%300==0){ //持久化 int []res=pstm.executeBatch(); //提交事务,持久化数据 con.commit(); pstm.clearBatch(); log.info("300整除插入结果: "+res.length); } } //小于300条的在这里持久化 int []ress= pstm.executeBatch(); //事务提交持久化 con.commit(); pstm.clearBatch(); log.info("插入数据结果:"+ress.length); } catch (SQLException e) { try { con.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); }finally{ try { if(null!=con){ con.close(); con.setAutoCommit(true); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
批量添加步骤最后总结:
-
url中添加rewriteBatchedStatements=true,如:
String url="jdbc:mysql://localhost:3306/MyTestBase?rewriteBatchedStatements=true;
- 将connection的自动提交关闭
con=JdbcUtil.getConnection();//自己实现的工具类,获取connection对象 con.setAutoCommit(false);
-
-
ResultSet
- Statement和PreparedStatement中都可以传入两个参数:ResultSetType和ResultSetConcurrency(名字自己取的,意思差不多,type在前,concurrency在后,但是都可单独传入)
ResultSet方法 | 作用 |
---|---|
public boolean next() | 顺序获取查询记录 |
public void beforeFrist() | 将游标移动到第一行之前 |
public void afterLast() | 将游标移到最后一行之后 |
public void first() | 将游标移动到结果集的第一行 |
public void last() | 将游标移动到结果集的最后一行 |
public boolean isAfterLast() | 判断游标是否在最后一行之后 |
public boolean isBeforefirst() | 判断游标是否在最后一行之前 |
public boolean isFirst() | 判断游标是否在结果集的第一行 |
public boolean isLast() | 判断游标是否在结果集的最后一行 |
public int getRow() | 得到当前游标所指行的行号,行号从1开始。如果结果集没有行,返回0 |
public boolean absolute(int row) | 将游标移动到参数row所指的行号 |
public boolean previous() | 将游标向上移动,该方法返回boolean型数据,当移动到结果集第一行的前面返回false |
type取值 | 作用 |
---|---|
ResultSet.TYPE_FORWARD_ONLY | 结果集的游标只能向下滚动 |
ResultSet.TYPE_SCROLL_INSENSITIVE | 结果集的游标可以上下移动,当数据库变化时,当前结果集不变 |
ResultSet.TYPE_SCROLL_SENSITIVE | 返回可滚动的结果集,当数据库变化时,结果集同步变化 |
Concurrency取值 | 作用 |
---|---|
ResultSet.CONCUR_READ_ONLY | 不能用结果集更新数据库中的表 |
ResultSet.CONCUR_UPDATABLE | 能用结果集更新数据库中的表 |
-
ResultSetMetaData
ResultSet rs=ps.executeQuery(); ResultSetMetaData metaData=rs.getMetaData();
ResultSetMetaData中保存的结果集的列,如:姓名,班级等
-
CachedRowSetImpl
CachedRowSetImpl可以保存ResultSet对象中的数据,并且CachedRowSetImpl不依赖connection对象,因此,查询CachedRowSetImpl时可以关闭和数据库的连接