基本概念:
第一个知识点:事务(transaction交易的意思):
事务是不可分割的,也就是原子性,例如转账,涉及到两个select语句,这两条语句要么全部执行,要么全部不执行
事务是有结构的:在java中靠的是异常处理,在try语句块中写内容(就是异常处理结构)
内容是:
1.开启一个事务:conn.setAuotCommit(false)手动提交
2.执行sql1,执行sql2.....执行sqln(执行多条语句)
3.提交conn.commit()
如果发生异常,将在catch中执行回滚:4.conn.rollback();
最后在finally中关闭数据库资源
onn.commit()和conn.rollback()是边界语句
-----
自动提交的单位是一条sql语句,关闭自动提交并使用commit就一次执行多条了
设置成非自动提交,我们就认为这句话是开启事务,因为执行多条语句了(事务就是在执行多条数据)
在执行多条sql语句的时候是先把sql语句的结果放在缓存里,当commit的时候才正式提交
注意:连接对象是事务的前提,commit和rollback是事务的正常关闭和异常关闭。conn开启的,也要conn结束。
第二个知识点:关于分页:
第一.使用滚动结果集分页:其实就是在以前正常的查询的基础上加了一些东西
思路:1.在方法上加两个形式参数,分别代表页数page和每页的记录数pagesize
2.在使用createStatement方法的时候,给这个方法加上两个参数,让这个方法创建的语句对象能够滚动只读。
3.执行sql语句产生结果集对象,然后给结果集对象绝对定位,定位到begin位置,begin是通过两个形参做运算之后的结果(这也就是形参的作用了)
绝对定位能够定位到某一页的第一行记录。
4.定位到某一页的第一行记录之后,就开始for循环,循环遍历这一页的每行内容。
5.考虑到最后一页可能数据不足,写一个if语句if(!rs.next()){break}
注意:在方法体中要先利用参数算出起始行。
滚动结果集的缺点:滚动结果集能够上下滚动,还能够绝对定位和相对定位,之所以能够实现这些功能,是因为在使用滚动结果集的时候,
他把每一条记录都加上了一个链表,这样把每一条记录都连接到了一起。但是,这样就导致一个缺点,就是会对客户端和
服务器端的内存带来极大的消耗,因此不能处理海量数据。
第二:使用select语句完成分页功能:其实跟以前正常些的查询语句一样,不一样的地方就是select语句不一样
思路:1.就是在select语句中下文章,如果想对某个表进行分页查询,先给这个表中的记录加上行号,使用rownum就能够加上行号。
2.现在要操作的是这个带行号的表,也就是要查询的是这个带行号的表,在查询的时候对这个表加上where条件,条件是
查询记录从哪条开始,哪条结束
注意:在方法体中要先利用形式参数算出要查询的起始行和结束行
区别:第一种由于需要用到滚动结果集,但是滚动结果集在Statement接口中,因此要使用createStatement方法给他分配结果集的滚动参数。
第二种分页由于在复杂select语句中用到了?传值的形式,因此是预编译语句,要使用PrepareStatement。
第一种分页:是个for循环,因此有必要判断!rs.next()。注意:这种滚动结果集的方式只是在上面一行代码中定位了这一页的起始行,但是并没有结束行,如果用
while语句循环的话,就相当于从当前记录一直循环到最后一条记录了。为了只循环这一页,因此使用for循环,循环条件是i小于这个页的总行数。
for(int i=1;i<=pagesize;i++){
System.out.println(rs.getString("cid")+" "+rs.getString("cname")+" "+rs.getInt("xf"));
if(!rs.next()){
break;
}
}
第二种分页:用的是while循环,当条件满足才会进循环,因此不用考虑条件不满足的情况,也就是不用!rs.next()。注意:这行while循环上面设置了起始行的位置和
结束行的位置,因此可以用while循环。也就是说select语句中已经规定好了起始行和结束行。
while(rs.next()){
System.out.println(rs.getString("cid")+" "+rs.getString("cname")+" "+rs.getInt("xf"));
}
代码实现:
第一:使用批处理executeBatch,完成事务操作
package updateTest;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Random;
import comm.dbHandler;
//关于批处理executeBatch,批处理添加。批处理就是在事务的基础上使用executeBatch
//事务提交的方式是事务之内的所有语句都会一起提交,批处理是在事务的基础上加了executeBatch,也就是不是所有的执行语句一起提交,而是规定每次提交几个
public class TestBatch {
private static ResultSet rs=null;
public static int executeBatch(){
//String sql="insert into cou values(?,?,?)";
String sql="insert into cou "+" values(?,?,?)";
Connection conn=dbHandler.getConnection();
PreparedStatement pstmt=null;
int count=0;
try {
conn.setAutoCommit(false);
pstmt=conn.prepareStatement(sql);
Random random=new Random();
for(int i=1;i<=4;i++){//这里说明一共有4条数据
int xuefen=2+random.nextInt(20-2+1);
pstmt.setString(1, "3"+i);
pstmt.setString(2, "同学"+i);
pstmt.setInt(3, xuefen);
pstmt.addBatch();//添加到批处理
count++;
if(i%10==0){//当批量处理列表中积累了10条sql语句
//通过预备语句对象,一次性执行批处理列表中的
//10条sql语句
pstmt.executeBatch();//当缓存中有十条语句的时候就执行这批语句。从客户端发送到服务器端,从java程序发送到oracle。(一边发送一边处理)
//清空批处理列表
pstmt.clearBatch();//清空这一批列表,准备接受下一批
}
}
pstmt.executeBatch();//这是给最后一次用的
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
count=0;//注意回滚后把数清零
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
return count;
}
public static void main(String[] args) {
int n=executeBatch();
System.out.println(n);
}
}
第二:不使用批处理executeBatch,完成事务操作
package updateTest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import comm.dbHandler;
/**针对user表,编写一个Java应用程序,该程序提供一个修改用户email的方法,要求将email设置成"用户名@sina.com"。这个修改方法的签名如下:
updateEmail(int id),id指的是用户的编号。更新完成之后,通过查询显示更新的结果。
*
*/
//注意:这里面每个方法都是可以用的
public class chu {
private static Statement stmt=null;
//private static Connection conn=dbHandler.getConnection();//打开连接,这虽然是每个方法都会用到的,但是如果这个方法当成全局变量,只能操作一个方法,当操作多一个方法的时候连接已经关闭。因为这个属性要在每个方法中重复声明一次
private static PreparedStatement pstmt=null;
private static ResultSet rs=null;
//不带参数的方法
/* public static void updateing(){
Connection conn=dbHandler.getConnection();
String sql="update book set name='java面向对象' where id=?";
//String sql="update book set name='java面向对象'";
int rows=0;
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 1002);
rows=pstmt.executeUpdate();
if(rows==1){
System.out.println("修改成功");
chu.search();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
}
//带参数的方法
public static void updateing(int bid){
Connection conn=dbHandler.getConnection();
String sql="update book set name='java面向对象' where id=?";
int rows=0;
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, bid);
rows=pstmt.executeUpdate();
if(rows==1){
System.out.println("修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
}*/
//带参数的方法
public static void updateing1(int bid){
Connection conn=dbHandler.getConnection();
String sql="update book set name=? where id="+bid;
int rows=0;
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, getUserName(bid)+"a");
/*if(getUserName(bid) instanceof String){
System.out.println(Integer.parseInt(getUserName(bid))+111);
}*/
rows=pstmt.executeUpdate();
if(rows==1){
chu.search();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
}
/*//不带参数,但是使用了事务
public static int updateing1(){
Connection conn=dbHandler.getConnection();
int count=0;
String[] sqls={
"update book set name='十万个为什么' where id=1004",
"update book set DESCRIPTION='这里是描述' where id=1002",
"update book set DESCRIPTION='这里是描述' where id=1002"
};
try {
conn.setAutoCommit(false);
stmt=conn.createStatement();
for(int i=0;i<sqls.length;i++){
stmt.executeUpdate(sqls[i]);
count++;
}
conn.commit();
} catch (SQLException e) {
try {
conn.rollback();
count=0;
System.out.println("回滚");
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("异常");
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
return count;
}*/
/*//不带参数,但是使用了事务,现在用这个方法做作业
public static int updateing2(){
Connection conn=dbHandler.getConnection();
int count=0;
String[] sqls={
"update book set name='struts2实战经典?!!' where id=1001",
"select * from book where id=1002",
"update book set description='重写描述与一下111' where id=1002",
};
try {
conn.setAutoCommit(false);//开启事务
stmt=conn.createStatement();
for(int i=0;i<sqls.length;i++){
Boolean b=stmt.execute(sqls[i]);//执行,用execute
//System.out.println("111111111"+b);
count++;
if(count==sqls.length){//如果都执行过
chu.search();//调用查询全部这个函数
}
}
conn.commit(); //提交
} catch (SQLException e) {
try {
conn.rollback();//回滚
count=0;
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
return count;
}*/
//使用了事务,使用了问号,没用executeBatch(批处理),跟executeBatch一样的效果
public static int updateing3(){
Connection conn=dbHandler.getConnection();
int count=0;
String sql="insert into book values(?,?,?)";
try {
conn.setAutoCommit(false);//开启事务
pstmt=conn.prepareStatement(sql);
for(int i=1;i<=3;i++){
pstmt.setInt(1, 10+i);
pstmt.setString(2, "这是书名"+i);
pstmt.setString(3, "这是描述"+i);
pstmt.executeUpdate();
count++;
}
conn.commit(); //提交
} catch (SQLException e) {
try {
conn.rollback();//回滚
count=0;
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
return count;
}
//查询,当修改成功之后调用这个方法
public static void search(){
Connection conn=dbHandler.getConnection();
String sql="select * from book";
try {
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(sql);
ResultSetMetaData md = rs.getMetaData();
int colsCount = md.getColumnCount();
while(rs.next()){
for(int i=1;i<=colsCount;i++){
System.out.print(rs.getObject(i)+" ");
}
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
}
public static String getUserName(int bid){
String u=null;
Connection conn=dbHandler.getConnection();
//String sql="select * from book"+" where id="+bid;
String sql="select * from book"+" where id="+bid;
try {
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(sql);
rs.next();
u=rs.getString("name");
//System.out.println("成功");
} catch (SQLException e) {
e.printStackTrace();
}
/*finally{
dbHandler.getClose(rs, pstmt, conn);
}*/
return u;
}
public static void main(String[] args) {
//updateing();
updateing1(1002);
/*int n=updateing1();
System.out.println("执行条数"+n);*/
//search();
//int n=updateing2();
//updateing3();
//getUserName(1002);
}
}
第三:第一种分页查询:利用滚动结果集进行分页查询
package updateTest;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import comm.dbHandler;
//利用滚动结果集进行分页查询
public class TestBufferPage {
public static void getPage(int page,int pagesize){
Statement stmt=null;
ResultSet rs=null;
int begin=(page-1)*pagesize+1;//每页的起始行数,这个很重要
Connection conn=dbHandler.getConnection();
String sql="select * from cou";
try {
//createStatement默认情况下是只进只读,现在加了参数,让他变成了滚动,只读
stmt=conn.createStatement
(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);//滚动,只读
rs=stmt.executeQuery(sql);
rs.absolute(begin);//绝对定位到这一页的begin位置,也就是这一页的第一行
for(int i=1;i<=pagesize;i++){
//System.out.println("成功");
System.out.println(rs.getString("cid")+" "+rs.getString("cname")+" "+rs.getInt("xf"));
if(!rs.next()){//rs表示这一行,这句话是说这一行没数据的时候就退出。在最后一次,如果数据不够pagesize,当没有数据的时候就退出
break;
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, stmt, conn);
}
}
public static void main(String[] args) {
getPage(5,4);
}
}
第四:第二种分页查询:利用复杂select语句进行分页查询
package updateTest;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import comm.dbHandler;
//复杂select语句分页
public class 分页2 {
public static void page(int page,int pagesize){
String sql="select cid,cname,xf from cou";
String sql1="select cid,cname,xf from cou order by cid desc ";//1.这是将这个表降序
String sql2="select rownum rn,cid,cname,xf from(select cid,cname,xf from cou order by cid desc)";//2.根据1的结果写出行号,rownum这是系统给的用来记录行号的
//3.在2的基础上,加上where条件,两个问号分别是两个参数。
String sql3="select cid,cname,xf from " +
"(select rownum rn,cid,cname,xf from " +
"(select cid,cname,xf from cou order by cid desc)) " +
"where rn between ? and ?";
Connection conn=dbHandler.getConnection();
PreparedStatement pstmt = null;
ResultSet rs=null;
int begin=(page-1)*pagesize+1;//起始行
int end=begin+pagesize-1;//结束行
try {
pstmt=conn.prepareStatement(sql3);
pstmt.setInt(1, begin);
pstmt.setInt(2, end);
rs=pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString("cid")+" "+rs.getString("cname")+" "+rs.getInt("xf"));
if(!rs.next()){
break;
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
dbHandler.getClose(rs, pstmt, conn);
}
}
public static void main(String[] args) {
page(1,6);
}
}