J2EE进阶之JDBC分页,大文本数据存储,批处理,事物处理 十八

23 篇文章 0 订阅
14 篇文章 0 订阅

分页,批处理,大文本数据存储,事物处理

分页

1:MySQL数据库的支持:

Select * from table limit M,N
  **M:记录开始索引位置
  N:取多少条记录。**

需求:

每页显示10条记录:
第一页:SELECT * FROM customers LIMIT 0,10
第二页:SELECT * FROM customers LIMIT 10,10
第三页:SELECT * FROM customers LIMIT 20,10
第x页:SELECT * FROM customers LIMIT (x-1)*10,10

总共多少页:
总条数%10==0?总条数/10:总条数/10+1;

以上一个项目对表单的操作为例:

2:设计一个类,封装了所有与分页有关的信息

完成WEB页面的分页显示

先获得需分页显示的记录总数,然后在web页面中显示页码。
根据页码,从数据库中查询相应的记录显示在web页面中。

以上两项操作通常使用Page对象进行封装。

page代码:

  1 package jdbcdemo2.com.wsj.commons;
  2 
  3 import java.util.List;
  4 
  5 /**
  6  * 封装所有与分页有关的信息
  7  * @author Angus
  8  *
  9  */
 10 public class Page {
 11     private List records;//要显示的分页数据
 12     private int currentPageNum = 1;//当前页码。默认应该为1
 13     private int totalPageCount;//总页数:可以计算
 14     private int totalRecordsNum;//总记录条数
 15     private int pageSize = 10;//每页显示的条数
 16     private int startIndex;//每页开始记录的索引:可以计算
 17     private int prePageNum;//上一页的页码
 18     private int nextPageNum;//下一页的页码
 19     
 20     private String uri;//查询分页的地址路径
 21     //-------------------------
 22     private int startPage;//页码:开始页码
 23     private int endPage;//页码:结束页码
 24     //-------------------------
 25     public Page(int currentPageNum,int totalRecordsNum){
 26         this.currentPageNum = currentPageNum;
 27         this.totalRecordsNum = totalRecordsNum;
 28         //计算总页数
 29         totalPageCount = totalRecordsNum%pageSize==0?totalRecordsNum/pageSize:totalRecordsNum/pageSize+1;
 30         //计算每页开始记录的索引
 31         startIndex = (currentPageNum-1)*pageSize;
 32         
 33         //计算开始页码和结束页码
 34         if(totalPageCount<=9){
 35             startPage = 1;
 36             endPage = totalPageCount;
 37         }else{
 38             //总页数大于9
 39             startPage = currentPageNum-4;
 40             endPage = currentPageNum+4;
 41             if(startPage<1){
 42                 startPage = 1;
 43                 endPage = 9;
 44             }
 45             if(endPage>totalPageCount){
 46                 endPage = totalPageCount;
 47                 startPage = endPage-8;
 48             }
 49         }
 50         
 51         
 52     }
 53     public int getPrePageNum() {
 54         prePageNum = currentPageNum-1;
 55         if(prePageNum<1)
 56             prePageNum = 1;
 57         return prePageNum;
 58     }
 59     public int getNextPageNum() {
 60         nextPageNum = currentPageNum+1;
 61         if(nextPageNum>totalPageCount)
 62             nextPageNum = totalPageCount;
 63         return nextPageNum;
 64     }
 65 
 66     public void setPrePageNum(int prePageNum) {
 67         this.prePageNum = prePageNum;
 68     }
 69 
 70     public List getRecords() {
 71         return records;
 72     }
 73 
 74     public void setRecords(List records) {
 75         this.records = records;
 76     }
 77 
 78     public int getCurrentPageNum() {
 79         return currentPageNum;
 80     }
 81 
 82     public void setCurrentPageNum(int currentPageNum) {
 83         this.currentPageNum = currentPageNum;
 84     }
 85 
 86     public int getTotalPageCount() {
 87         return totalPageCount;
 88     }
 89 
 90     public void setTotalPageCount(int totalPageCount) {
 91         this.totalPageCount = totalPageCount;
 92     }
 93 
 94     public int getTotalRecordsNum() {
 95         return totalRecordsNum;
 96     }
 97 
 98     public void setTotalRecordsNum(int totalRecordsNum) {
 99         this.totalRecordsNum = totalRecordsNum;
100     }
101 
102     
103 
104     public void setNextPageNum(int nextPageNum) {
105         this.nextPageNum = nextPageNum;
106     }
107 
108     public int getPageSize() {
109         return pageSize;
110     }
111 
112     public void setPageSize(int pageSize) {
113         this.pageSize = pageSize;
114     }
115 
116     public int getStartIndex() {
117         return startIndex;
118     }
119 
120     public void setStartIndex(int startIndex) {
121         this.startIndex = startIndex;
122     }
123     public int getStartPage() {
124         return startPage;
125     }
126     public void setStartPage(int startPage) {
127         this.startPage = startPage;
128     }
129     public int getEndPage() {
130         return endPage;
131     }
132     public void setEndPage(int endPage) {
133         this.endPage = endPage;
134     }
135     public String getUri() {
136         return uri;
137     }
138     public void setUri(String uri) {
139         this.uri = uri;
140     }
141     
142 }

3:改造Service接口

BusinessService接口

/**
 * 根据用户要看的页码,查询封装了所有分页信息有关的Page对象
 * @param pageNum 如果为null,则默认值是1
 * @return
 */
Page findPageRecords(String pageNum);

BusinessServiceImpl实现

@Override
public Page findPageRecords(String pageNum) {
    int currentPageNum = 1;
    if(pageNum!=null){
        currentPageNum = Integer.parseInt(pageNum);
    }
    int totalRecordsNum = dao.findTotalRecordsNum();// 查询记录的总条数
    Page page = new Page(currentPageNum, totalRecordsNum);
    //把记录搞到page中
    List<Customer> records = dao.findPageRecords(page.getStartIndex(),page.getPageSize());//查询分页记录
    page.setRecords(records);
    return page;
}

4:改造DAO层

CustomerDao接口

/**
 * 查询记录总条数
 * @return
 */
int findTotalRecordsNum();
/**
 * 根据索引和大小查询分页记录
 * @param startIndex
 * @param pageSize
 * @return
 */
List<Customer> findPageRecords(int startIndex, int pageSize);

CustomerDaoMySQLImpl实现

@Override
public int findTotalRecordsNum() {
    try{
        conn = JDBCUtils.getConnection();
        stmt = conn.prepareStatement("select count(*) from customers");
        rs = stmt.executeQuery();
        if(rs.next()){
            return rs.getInt(1);
        }
        return 0;
    }catch(Exception e){
        throw new RuntimeException(e);
    }finally{
        JDBCUtils.release(rs, stmt, conn);
    }
}

@Override
public List<Customer> findPageRecords(int startIndex, int pageSize) {
    try{
        conn = JDBCUtils.getConnection();
        stmt = conn.prepareStatement("select * from customers limit ?,?");
        stmt.setInt(1, startIndex);
        stmt.setInt(2, pageSize);
        List<Customer> cs = new ArrayList<Customer>();
        rs = stmt.executeQuery();
        while(rs.next()){
            Customer c = new Customer();
            c.setId(rs.getString("id"));
            c.setName(rs.getString("name"));
            c.setGender(rs.getString("gender"));
            c.setBirthday(rs.getDate("birthday"));
            c.setPhonenum(rs.getString("phonenum"));
            c.setEmail(rs.getString("email"));
            c.setHobby(rs.getString("hobby"));
            c.setType(rs.getString("type"));
            c.setDescription(rs.getString("description"));
            cs.add(c);
        }
        return cs;
    }catch(Exception e){
        throw new RuntimeException(e);
    }finally{
        JDBCUtils.release(rs, stmt, conn);
    }
}

5;改造Servlet

// 查询所有客户信息
private void showAllCustomers(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    // 获取用户要看的页面:参数num
    String num = request.getParameter("num");
    Page page = s.findPageRecords(num);
    page.setUri("/CentrolServlet?op=showAllCustomers");
    // 封装数据到域对象中
    request.setAttribute("page", page);
    request.getRequestDispatcher("/listCustomers.jsp").forward(request,
            response);
} 

6、改造页面

  1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  4 <html>
  5   <head>
  6     <title>显示所有客户信息</title>
  7     
  8     <meta http-equiv="pragma" content="no-cache">
  9     <meta http-equiv="cache-control" content="no-cache">
 10     <meta http-equiv="expires" content="0">
 11     <!--
 12     <link rel="stylesheet" type="text/css" href="styles.css">
 13     -->
 14     <style type="text/css">
 15         .odd{
 16             background-color: #c3f3c3;
 17         }
 18         .even{
 19             background-color: #f3c3f3;
 20         }
 21     </style>
 22   </head>
 23   
 24   <body>
 25     <table width="88%">
 26         <tr>
 27             <td>
 28                 <a href="${pageContext.request.contextPath}/addCustomer.jsp">添加</a>
 29                 <a href="javascript:delMulti()">删除</a>
 30             </td>
 31         </tr>
 32         <tr>
 33             <td>
 34             <form action="${pageContext.request.contextPath}/ControlServlet?op=delMultiCustomer" method="post"></form>
 35                 <table border="1" width="100%">
 36                     <tr>
 37                         <th>选择</th>
 38                         <th>姓名</th>
 39                         <th>性别</th>
 40                         <th>生日</th>
 41                         <th>手机</th>
 42                         <th>邮件</th>
 43                         <th>爱好</th>
 44                         <th>类型</th>
 45                         <th>备注</th>
 46                         <th>操作</th>
 47                     </tr>
 48                     <!-- 从page.records 取分页数据 -->
 49                     <c:forEach items="${page.records}" var="c" varStatus="vs">
 50                         <tr class="${vs.index%2==0?'odd':'even' }">
 51                             <td>
 52                                 <input type="checkbox" name="ids" value="${c.id}">
 53                             </td>
 54                             <td>${c.name}</td>
 55                             <td>${c.gender=='male'?'男':'女' }</td>
 56                             <td>${c.birthday}</td>
 57                             <td>${c.phonenum}</td>
 58                             <td>${c.email}</td>
 59                             <td>${c.hobby}</td>
 60                             <td>${c.type}</td>
 61                             <td>${c.description}</td>
 62                             <td>
 63                                 [<a href="${pageContext.request.contextPath}/ControlServlet?op=editCustomerUI&customerId=${c.id}">修改</a>]
 64                                 [<a href="javascript:delOne('${c.id}')">删除</a>]
 65                             </td>
 66                         </tr>
 67                     </c:forEach>
 68                 </table>
 69             </td>
 70         </tr>
 71         
 72         <tr>
 73             <td>
 74                 <!-- 分页开始 -->
 75                 
 76                 第${page.currentPageNum}页/共${page.totalPageCount}页&nbsp;&nbsp;
 77                 <a href="${pageContext.request.contextPath}">首页</a>&nbsp;&nbsp;
 78                 <a href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num=  ${page.prePageNum}">上一页</a>&nbsp;&nbsp;
 79                 <a href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num=${page.nextPageNum}">下一页</a>&nbsp;&nbsp;
 80                 <a href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num=${page.totalPageCount}">尾页</a>&nbsp;&nbsp;
 81             
 82             </td>
 83         
 84         </tr>
 85     </table>
 86     
 87     <script type="text/javascript">
 88     function delOne(customerId){
 89         var sure = window.confirm("确定要删除吗?");
 90         if(sure){
 91             window.location.href="${pageContext.request.contextPath}/ControlServlet?op=delOneCustomer&customerId="+customerId;
 92         }
 93     }
 94     function delMulti(){
 95         //得到所有的name=ids的对象
 96         var idsObj = document.getElementsByName("ids");
 97         //判断用户有没有选择
 98         var selected = false;
 99         for(var i=0;i<idsObj.length;i++){
100             if(idsObj[i].checked){
101                 selected = true;
102                 break;
103             }
104         }
105         //没有选择的提示
106         if(!selected){
107             alert("笨蛋,删除前请先选择");
108             return;
109         }
110         //用户选择了
111         var sure = window.confirm("确定要删除所选记录吗?");
112         if(sure){
113             document.forms[0].submit();
114         }
115     }
116     
117     </script>
118   </body>
119 </html>

效果图:

6.2:页面选择跳转

实现代码:

<select onchange="jupm(this)">
                <c:forEach begin="1" end="${page.totalPageCount}" var = "num">
                    <option value = "${num }" ${page.currentPageNum==num?'selected="selected"':'' }>${num} </option>

                </c:forEach>

</select>

<script type="text/javascript">
                function jupm(selectObj){
                    //alert(selectObj.value); 

                    var pageNum = selectObj.value;
                    window.location.href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num="+pageNum;
                }

</script>
6.3输入任意跳转

代码实现

<input id="num" name="num" value="" size="3"/>
<input type="button" value="跳转" onclick="jumpPage()"/>

function jumpPage(){
    var num = document.getElementById("num").value;
    //alert(num);
    window.location.href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num="+num;
}
6.4 模仿百度搜索页数

<c:forEach begin="${page.startPage }" end="${page.endPage }" var="num">
            <a href="${pageContext.request.contextPath}/ControlServlet?op=showAllCustomers&num=${num}">${num}</a>


</c:forEach>

page代码

//-------------------------
private int startPage;//页码:开始页码
private int endPage;//页码:结束页码
//-------------------------
public Page(int currentPageNum,int totalRecordsNum){
    this.currentPageNum = currentPageNum;
    this.totalRecordsNum = totalRecordsNum;
    //计算总页数
    totalPageCount = totalRecordsNum%pageSize==0?totalRecordsNum/pageSize:totalRecordsNum/pageSize+1;
    //计算每页开始记录的索引
    startIndex = (currentPageNum-1)*pageSize;

    //计算开始页码和结束页码
    if(totalPageCount<=9){
        startPage = 1;
        endPage = totalPageCount;
    }else{
        //总页数大于9
        startPage = currentPageNum-4;
        endPage = currentPageNum+4;
        if(startPage<1){
            startPage = 1;
            endPage = 9;
        }
        if(endPage>totalPageCount){
            endPage = totalPageCount;
            startPage = endPage-8;
        }
    }


}

批处理

业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。

实现批处理有两种方式,第一种方式:

  Statement.addBatch(sql) list
执行批处理SQL语句
  executeBatch()方法:执行批处理命令
  clearBatch()方法:清除批处理命令

public void test1(){
    Connection conn = null;
    Statement stmt = null;
    try{
        conn = JdbcUtil.getConnection();
        stmt = conn.createStatement();

        String sql1 = "insert into t1(id,name) values(1,'aa1')";
        String sql2 = "insert into t1(id,name) values(2,'aa2')";
        String sql3 = "delete from t1 where id=1";


        //stmt对象中有一个List,这就sql语句的缓存。
        stmt.addBatch(sql1);
        stmt.addBatch(sql2);
        stmt.addBatch(sql3);

        int ii[] = stmt.executeBatch();//真正执行.返回的值是每条语句影响到的行数的数组
        for(int i:ii)
            System.out.println(i);
    }catch(Exception e){
        throw new RuntimeException(e);
    }finally{
        JdbcUtil.release(null, stmt, conn);
    }
}

总结:采用Statement.addBatch(sql)方式实现批处理:
**优点:可以向数据库发送多条不同的SQL语句。
缺点:
SQL语句没有预编译。
当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句**。例如:

    Insert into user(name,password) values(‘aa’,’111’);
    Insert into user(name,password) values(‘bb’,’222’);
    Insert into user(name,password) values(‘cc’,’333’);
    Insert into user(name,password) values(‘dd’,’444’);

实现批处理的第二种方式:

PreparedStatement.addBatch()
注意内存溢出问题

//想t1中插入10条记录:语句不变,参数不同而已。而PreparedStatement就代表一条语句。
@Test
public void test2(){
    Connection conn = null;
    PreparedStatement stmt = null;
    try{
        conn = JdbcUtil.getConnection();
        stmt = conn.prepareStatement("insert into t1(id,name) values(?,?)");
        //批量设置参数
        for(int i=0;i<10;i++){
            stmt.setInt(1, i+1);
            stmt.setString(2, "aaa"+(i+1));
            stmt.addBatch();
        }

        int ii[] = stmt.executeBatch();//真正执行.返回的值是每条语句影响到的行数的数组
        for(int i:ii)
            System.out.println(i);
    }catch(Exception e){
        throw new RuntimeException(e);
    }finally{
        JdbcUtil.release(null, stmt, conn);
    }
}

//批量插入1001条记录
@Test
public void test3(){
    Connection conn = null;
    PreparedStatement stmt = null;
    try{
        conn = JdbcUtil.getConnection();
        stmt = conn.prepareStatement("insert into t1(id,name) values(?,?)");
        //批量设置参数
        for(int i=0;i<1001;i++){
            stmt.setInt(1, i+1);
            stmt.setString(2, "aaa"+(i+1));
            stmt.addBatch();
            //每100条就让数据库执行一次
            if(i%100==0){
                stmt.executeBatch();//执行
                stmt.clearBatch();//清空已经在缓存中的参数
            }
        }
        stmt.executeBatch();//执行

    }catch(Exception e){
        throw new RuntimeException(e);
    }finally{
        JdbcUtil.release(null, stmt, conn);
    }
}

总结:
采用PreparedStatement.addBatch()实现批处理
优点:发送的是预编译后的SQL语句,执行效率高。
缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据

大文本和二进制数据存储(了解)

在实际开发中,程序一般不需要把大文本或二进制数据保存到数据库。

基本概念:大数据也称之为LOB(Large Objects),LOB又分为:
clob和blob
 clob用于存储大文本。
 blob用于存储二进制数据,例如图像、声音、二进制文等。

对MySQL而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
 TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
 TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB

ClobDemo

  1 public class ClobDemo {
  2     @Test
  3     public void write(){
  4         Connection conn = null;
  5         PreparedStatement stmt = null;
  6         ResultSet rs = null;
  7         try{
  8             conn = JdbcUtil.getConnection();
  9             stmt = conn.prepareStatement("insert into t2 (id,content) values(?,?)");
 10             stmt.setInt(1, 1);
 11             //用流的形式
 12             File file = new File("src/海底捞.txt");
 13             Reader reader = new FileReader(file);
 14             stmt.setCharacterStream(2, reader, (int)file.length());//JDK6.0 setCharacterStream(int index,Reader r,long lengh)MySQL驱动没有实现
 15             stmt.executeUpdate();
 16         }catch(Exception e){
 17             e.printStackTrace();
 18         }finally{
 19             JdbcUtil.release(rs, stmt, conn);
 20         }
 21     }
 22     @Test
 23     public void read(){
 24         Connection conn = null;
 25         PreparedStatement stmt = null;
 26         ResultSet rs = null;
 27         try{
 28             conn = JdbcUtil.getConnection();
 29             stmt = conn.prepareStatement("select * from t2 where id=1");
 30             rs = stmt.executeQuery();
 31             if(rs.next()){
 32                 Reader reader = rs.getCharacterStream("content");
 33                 //存到D盘上
 34                 Writer writer = new FileWriter("d:/hdl.txt");
 35                 char buf[] = new char[1024];
 36                 int len = -1;
 37                 while((len=reader.read(buf))!=-1){
 38                     writer.write(buf, 0, len);
 39                 }
 40                 reader.close();
 41                 writer.close();
 42             }
 43         }catch(Exception e){
 44             e.printStackTrace();
 45         }finally{
 46             JdbcUtil.release(rs, stmt, conn);
 47         }
 48     }
 49 }

BlobDemo

  1 public class BlobDemo {
  2     @Test
  3     public void write(){
  4         Connection conn = null;
  5         PreparedStatement stmt = null;
  6         ResultSet rs = null;
  7         try{
  8             conn = JdbcUtil.getConnection();
  9             stmt = conn.prepareStatement("insert into t3 (id,content) values(?,?)");
 10             stmt.setInt(1, 1);
 11             //用流的形式
 12             InputStream in = new FileInputStream("src/19.jpg");
 13             stmt.setBinaryStream(2, in, in.available());//JDK6.0 setCharacterStream(int index,Reader r,long lengh)MySQL驱动没有实现
 14             stmt.executeUpdate();
 15         }catch(Exception e){
 16             e.printStackTrace();
 17         }finally{
 18             JdbcUtil.release(rs, stmt, conn);
 19         }
 20     }
 21     @Test
 22     public void read(){
 23         Connection conn = null;
 24         PreparedStatement stmt = null;
 25         ResultSet rs = null;
 26         try{
 27             conn = JdbcUtil.getConnection();
 28             stmt = conn.prepareStatement("select * from t3 where id=1");
 29             rs = stmt.executeQuery();
 30             if(rs.next()){
 31                 InputStream in = rs.getBinaryStream("content");
 32                 //存到D盘上
 33                 OutputStream out = new FileOutputStream("d:/jj.jpg");
 34                 byte buf[] = new byte[1024];
 35                 int len = -1;
 36                 while((len=in.read(buf))!=-1){
 37                     out.write(buf, 0, len);
 38                 }
 39                 in.close();
 40                 out.close();
 41             }
 42         }catch(Exception e){
 43             e.printStackTrace();
 44         }finally{
 45             JdbcUtil.release(rs, stmt, conn);
 46         }
 47     }
 48 }

事物

事务的概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
例如:A——B转帐,对应于如下两条sql语句
 update account set money=money-100 where name=‘a’;
 update account set money=money+100 where name=‘b’;
数据库开启事务命令DTL

  • -start transaction 开启事务
  • -Rollback 回滚事务
  • -Commit 提交事务

      1 public class TransactionDemo {
      2     //模拟转账
      3     @Test
      4     public void test1(){
      5         Connection conn = null;
      6         PreparedStatement stmt = null;
      7         ResultSet rs = null;
      8         try{
      9             conn = JdbcUtil.getConnection();
     10             conn.setAutoCommit(false);//相当于开启事务:start transaction
     11             stmt = conn.prepareStatement("update account set money=money-100 where name='bbb'");
     12             stmt.executeUpdate();
     13 //          int i=1/0;
     14             stmt = conn.prepareStatement("update account set money=money+100 where name='aaa'");
     15             stmt.executeUpdate();
     16             conn.commit();
     17         }catch(Exception e){
     18             if(conn!=null){
     19                 try {
     20                     conn.rollback();
     21                 } catch (SQLException e1) {
     22                     e1.printStackTrace();
     23                 }
     24             }
     25             e.printStackTrace();
     26         }finally{
     27             JdbcUtil.release(rs, stmt, conn);
     28         }
     29         
     30     }
     31 }
    

事务的特性(ACID)

原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
 
一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

事务的隔离级别

多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性.

1、多线程机制下,不考虑把不同线程中的事务隔离起来,会导致什么问题?
脏读:指一个线程中的事务读到了另外一个线程中事务未提交的数据。
不可重复读:指一个线程中的事务读到了另外一个线程中提交的UPDATE的数据。
虚读(幻读):指一个线程中的事务读到了另外一个线程中提交的INSERT的数据。

2、解决以上问题:
更改事务的隔离级别:
1 READ UNCOMMITTED:脏读、不可重复读、虚读都有可能发生。
2 READ COMMITTED:防止脏读,不可重复读、虚读都有可能发生。
4 REPEATABLE READ:防止脏读、不可重复读,虚读有可能发生。
8 SERIALIZABLE:防止脏读、不可重复读、虚读的发生。
随着级别越高,数据越安全,但效率越低。

3、MySQL查看和更改事务的隔离级别
查看当前的隔离级别:SELECT @@TX_ISOLATION;
临时更改当前的隔离级别(一定要在开启事务前):
  SET TRANSACTION ISOLATION LEVEL 四个级别之一

  Connection中的setTransactionIsolation(int level)用于设置隔离级别
  Level:Connection中的常量

先设置隔离级别,在开启事务。
  Conn.setTransactionIsolation(Connection.*);
  Conn.setAutoCommit(false);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值