By
    
      zhpooer
    
  
    
    更新日期:
    
  
	
		
		
		
		
		大结果集分页
- 分页靠SQL支持, 不同数据库的分页语句是不通过的
- MySQL 分页语句 limit M,N
 M: 开始记录的数据, 第一页的第一条索引是0
 N: 每次取出多少条
| 1
2
3
4
5
6
7
8
9
 | 
select * from customer limit 0, 10;
select * from customer limit 10, 10;
select * from customer limit (n-1)*10, 10;
 | 
对客户信息进行分页
新建Page类, 封装分页信息
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 | 
public class Page{
    private int pageSize; 
    private List recorder; 
    private int pageNum;  
    private int totalPage;  
    private int startIndex; 
    private int totalRecords; 
    public Page(intPageNum, int totalRecords){
        this.pageNum = pageNum;
        this.totalRecords = totalRecords;
        this.totalPage = totalRecords%pageSize==0?totalRecords/pageSize:totalRecords/pageSize+1;
        startIndex = (pageNum-1)*pageSize;
    }
}
 | 
改造接口DAO
| 1
2
3
4
5
6
7
 | public interface CustomerDao {
    @Deprecated
    List<Customer> findAll();
    int getTotalRecordsNum();
    List<Customer> findPageCustomers(int offset, int size);
}
 | 
改造业务代码
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 | public interface BusinessService{
    @Deprecated
    List<Customer> findAll();
    Page findPage(String pageNum)
}
public class BusinessServiceImpl{
    public Page findPage(String num) {
        int pageNum = 1;
        if(num!=null){
            pageNum = Integer.parseInt(num);
        }
        int totalRecords = dao.getTotalRecordsNum();
        Page page = new Page(pageNum, totalRecords);
        List<Customer> records = dao.findPageCustomers(page.statedIndex, page.pageSize);
        page.setRecords(records);
        return page;
    }
}
 | 
改造Servlet
| 1
2
3
4
5
6
 | private void showAllCustomer(){
   String num = request.getParameter("num")
   Page page = s.findPage(num)
   request.setAttribute("page", page)
   request.getRequestDispather("/listCustomer.jsp").forward(req, res)
}
 | 
改造JSP显示页面
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 | <c:if test="${!empty page}">
    <c:forEach items="page.records" var="c" varStatus="vs">
    </c:forEach>
</c:if>
第${page.pageNum}页   共${page.totalPage}页
<a href="${}/servlet/Controller?op=showAllCustomers&num=${pageNum-1<1?1:pageNum-1}">
</a>
<a href="${}/servlet/Controller?op=showAllCustomers&num=${pageNum+1>totalPage?totalPage:pageNum+1}">
</a>
// 跳页 方式一
<select id="num" name="num" onchange="jump(this)">
    <c:foreach begin="1" end="${}" var="i">
        <option value="${n}">${n}</option>
    </c:foreach>
</select>
function jump(select){
   window.location.href = "${}/servlet/Controller?op=showAllCustomers&num=" + select.value
}
// 跳页 方式二
<input type="text" size="3" name="num" id="num" value="${page.Naum}" /><a href="javascript:jump()"></a>
function fump(){
    var num = document.getElementsById("num").value
    var regObj = /^[1-9][0-9]*$/
    if(!regObj.test(num)) {
        alert("请正确输入")
        return;
    }
    if(num>${page.totalPage}){
        alert("页码超出范围");
        return;
    }
    window.location.href = "${}/servlet/Controller?op=showAllCustomers&num=" + num
}
 | 
提取代码
可以用静态包含, 提取公共jsp代码, 来复用代码
| 1
2
3
4
5
6
7
8
9
 | <%@ include file=""%>
public class Page {
    private String url = ""; 
}
public class Controller {
    page.setUrl("");
}
"${}/servlet/Controller?op=showAllCustomers&num=" + num 
"${}${page.url}&num=" + num
 | 
JDBC 大数据(LOB)的存取
大文本 CLOB(text)
| 1
2
3
4
 | create table t1(
    id int primary key,
    content longtext
)
 | 
存
| 1
2
3
4
5
6
7
8
 | Statement stmt = conn.PreparedStatement("insert into t1(id, content) value(?,?)");
stmt.setInt(1, 1);
File f = new File("test.txt");
Reader reader = new FileReader(f);
stmt.setCharacterStream(2, f, (int)f.length);
 | 
取
| 1
2
3
4
5
6
7
 | stmt = conn.PreparedStatement("select * from t1 where id=1");
stmt.excuteQuery();
if(rs.next()){
   Reader reader = re.getCharacterStream("content");
   Writer writer = new FileWriter("");
   ...
}
 | 
大二进制数据 BLOB
| 1
2
3
4
 | create table t1(
    id int primary key,
    content longblob
)
 | 
存, 取同 CBLOB, 核心方法:
- stmt.setBinaryStream(2, InputStream, length)
- stmt.getBinaryStream(2)
批处理
把sql语句缓存起来, 一起发给数据库, 减少数据库访问次数, 提高效率
| 1
2
3
4
 | create table t3 (
    id int primary key,
    name varchar(100)
)
 | 
- Statement | 1
2
3
4
5
6
7
8
 | Statement s1 = conn.createStatement();
String sql1 = "insert into t3 values(1, 'aaa1')"
String sql2 = "insert into t3 values(2, 'aaa2')";
String sql3 = "delete from t3 where id=1";
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
int ii[] = stmt.excuteBatch();  // 每条语句影响到的行数
 |  
 
- PreparedStatement | 1
2
3
4
5
6
7
8
9
10
11
12
 | PreparedStatement stmt = conn.prepareStatement("insert into t3 values(?,?)")
for(int i=1
   stmt.setInt(1, i)
   stmt.setString(2, "aaa" + i)
   stmt.addBatch()
   // 把准备好的参数加入到缓存中: 如果数据量太大, 内存可能溢出. 解决方案: 分批次执行
   if(i%100) {
      stmt.excuteBatch()
      stmt.clearBatch()
   }
}
stmt.excuteBatch()
 |  
 
调用存储过程
存储过程简介
| 1
2
3
4
5
6
7
8
9
10
 | -- 修改语句结束符号 ; => $$
delimiter $$
-- 创建一个存储过程, 名字为 demoSp,
--- 括号里面是参数, 形式: in|out|inout(输入或输出) 参数名字 参数类型
create procedure demoSp(In inputParam varchar(255), inout inOutParam varchar(255))
begin
    select concat('welcome to:', inputParam) into inOutParam;
end
delimiter ;
 | 
jdbc 调用存储过程
| 1
2
3
4
5
6
7
8
9
10
11
 | Connection conn = JdbcUtil.getConnection()
// 获取执行存储过程的对象
CallableStatement stmt = conn.prepareCall("{call demoSp(?,?)}")
// 设置参数, 输入参数要给一个值, 输出参数注册SQL数据类型
// 输入参数要给一个值
stmt.setString(1, "hch")
stmt.registerOutParameter(s, java.sql.Types.VARCHAR)
// 执行
stmt.excute()
String result = stmt.getString(2)
 | 
事务入门 (数据安全)
TPL: 事务(Transaction)处理语言
数据库有可能是自动提交事务的,(MySQL就是自动提交事务的),
每一条语句都是一个事务
- start Transaction: 开启事务
- rollback: 回滚, 回到最开始的地方
- commit: 提交, 永久存储到硬盘上
JDBC 操作事务
| 1
2
3
4
5
6
7
8
9
10
 | try {
    Connection conn = JdbcUtil.getConnection()
    conn.setAutoCommit(false)
    PreparedStatement stmt = conn.prepareStatement("")
    stmt.excuteUpdate()
    conn.commit()
    conn.setAutoCommit(true)
} finally{
   conn.rollback()
}
 |