一、大结果集的分页(重点,难点)
1、分批次查询:分页
2、基于数据库的分页:依赖的是数据库的分页语句(不同数据库是不同的)
MySQL:每页显示10条。
select * from XXX limit M,N;
M:开始记录的索引。第一条记录的索引为0.
N:一次查询几条记录。
第一页:select * from CUSTOMERS limit 0,10;
第二页:select * from CUSTOMERS limit 10,10;
......
第n页:select * from CUSTOMERs limit (n-1)*10,10;
总页数:
select count(*) from customers %10==0?select count(*) from customers /10:select count(*) from customers /10+1;
二、批处理:batch(练一遍)
<strong><span style="color: #ff0000;">降低与数据库的交互次数,提升执行效率</span></strong>
public class BatchDemo {
/*
create database day16;
use day16;
create table t1(
id int primary key,
name varchar(100)
);
*/
//向数据库中插入2条记录,再把第一条删除掉
//Statement可以批处理语句不同的。
@Test
public void test1() throws Exception{
Connection conn = JdbcUtil.getConnection();
Statement stmt = conn.createStatement();
String sql1 = "insert into t1 values(1,'aaa1')";
String sql2 = "insert into t1 values(2,'aaa2')";
String sql3 = "delete from t1 where id=1";
stmt.addBatch(sql1);//Statement实例内部有一个List,sql语句加到List中了
stmt.addBatch(sql2);
stmt.addBatch(sql3);
int[] ii = stmt.executeBatch();//返回值是一个数组,数组的元素为每条语句影响到的行数
for(int i:ii)
System.out.println(i);
JdbcUtil.release(null, stmt, conn);
}
//插入10条记录。PreparedStatement 适合语句相同,只是参数不通的情况
@Test
public void test2() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("insert into t1 values (?,?)");
for(int i=0;i<10;i++){
stmt.setInt(1, i+1);
stmt.setString(2, "aaaa"+(i+1));
stmt.addBatch();
}
stmt.executeBatch();
JdbcUtil.release(null, stmt, conn);
}
//插入1000001条记录。PreparedStatement 适合语句相同,只是参数不通的情况
@Test
public void test3() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("insert into t1 values (?,?)");
for(int i=0;i<1000001;i++){
stmt.setInt(1, i+1);
stmt.setString(2, "aaaa"+(i+1));
stmt.addBatch();
if(i%1000==0){
stmt.executeBatch();
stmt.clearBatch();//清理缓存
}
}
stmt.executeBatch();
JdbcUtil.release(null, stmt, conn);
}
}
三、Clob、Blob的读写(练一遍):文件上传
LOB:Large Object
Clob:Character Large Object字符(小说)
Blob:Binary Large Object二进制
//大数据的存取
public class LobDemo {
/*
create table t2(
id int,
content longtext
);
*/
@Test
public void test1() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("insert into t2 values (?,?)");
stmt.setInt(1, 1);
//以流的方式
File file = new File("src/jpm.txt");
Reader reader = new FileReader(file);
stmt.setCharacterStream(2, reader, (int)file.length());//PreparedStatement的实现是由数据库驱动提供的
//MySQL:setCharacterStream(int,Reader,long);根本没有实现。
//MySQL根本不支持那么大的数据。
stmt.executeUpdate();
JdbcUtil.release(null, stmt, conn);
}
//取大文本数据
@Test
public void test2() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("select * from t2 where id=1");
ResultSet rs = stmt.executeQuery();
if(rs.next()){
Reader r = rs.getCharacterStream("content");
//内容保存D盘的1.txt文件中
Writer w = new FileWriter("d:/1.txt");
int len = -1;
char c[] = new char[1024];
while((len=r.read(c))!=-1){
w.write(new String(c), 0, len);
}
r.close();
w.close();
}
JdbcUtil.release(rs, stmt, conn);
}
/*
create table t3(
id int,
content longblob
);
*/
@Test
public void test3() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("insert into t3 values (?,?)");
stmt.setInt(1, 1);
//以流的方式
InputStream in = new FileInputStream("src/26.jpg");
stmt.setBinaryStream(2, in, in.available());
stmt.executeUpdate();
JdbcUtil.release(null, stmt, conn);
}
@Test
public void test4() throws Exception{
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement("select * from t3 where id=1");
ResultSet rs = stmt.executeQuery();
if(rs.next()){
InputStream in = rs.getBinaryStream("content");
OutputStream out = new FileOutputStream("d:/wife.jpg");
int len = -1;
byte b[] = new byte[1024];
while((len=in.read(b))!=-1){
out.write(b,0,len);
}
in.close();
out.close();
}
JdbcUtil.release(null, stmt, conn);
}
}
四、如何调用存储过程
/*
delimiter $$
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam varchar(255))
BEGIN
SELECT CONCAT('zyxw---', inputParam) into inOutParam;
END $$
delimiter ;
*/
//如何调用已经存在的存储过程
public class CallableDemo {
@Test
public void test1() throws Exception{
Connection conn = JdbcUtil.getConnection();
CallableStatement stmt = conn.prepareCall("{call demoSp(?,?)}");
//输入参数:设置值
//输出参数:注册数据类型即可
stmt.setString(1, "YY");
stmt.registerOutParameter(2, Types.VARCHAR);
stmt.execute();
//打印执行的结果
System.out.println(stmt.getString(2));
JdbcUtil.release(null, stmt, conn);
}
}
五、事务入门(重点)
1、MySQL:每一条语句都属于独立事务,默认自动管理的。
2、开启事务:start transaction; 日后的语句都会处于同一个事务之中。
提交事务:commit;
回滚事务:rollback;
3、JDBC如何控制事务
//事务控制案例
/*
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
*/
public class TxDemo {
@Test
public void test1(){
Connection conn = null;
PreparedStatement stmt = null;
try{
conn = JdbcUtil.getConnection();
conn.setAutoCommit(false);//相当于start transaction
stmt = conn.prepareStatement("update account set money=money-100 where name='bbb'");
stmt.executeUpdate();
// int i=1/0;
stmt = conn.prepareStatement("update account set money=money+100 where name='aaa'");
stmt.executeUpdate();
conn.commit();// 提交事务
}catch(Exception e){
// if(conn!=null){
// try {
// conn.rollback();
// } catch (SQLException e1) {
// e1.printStackTrace();
// }
// }
throw new RuntimeException(e);
}finally{
JdbcUtil.release(null, stmt, conn);
}
}
}
六、事务的特性(重点。面试)
1、事务的特性:
原子性:处于事务中的多条语句是不可分割的。
一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如:转账,转账前A+B=2000,转账后A+B=2000
隔离性:多线程并发。一个事务不能被其他线程中的事务所打扰。
持久性:事务一旦提交,永久保存起来。
2、事务的隔离级别:属于事务的。都已开启了事务为前提。
不考虑事务的隔离级别,会出现以下情况(是错的)
l 脏读:一个线程中的事务读到了另外一个线程中未提交的数据。
l 不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据。
l 虚读:一个线程中的事务读到了另外一个线程中已经提交的insert的数据。
要想避免以上现象,通过更改事务的隔离级别来避免:
l READ UNCOMMITTED 脏读、不可重复读、虚读有可能发生。
l READ COMMITTED 避免脏读的发生,不可重复读、虚读有可能发生。
l REPEATABLE READ 避免脏读、不可重复读的发生,虚读有可能发生。
l SERIALIZABLE 避免脏读、不可重复读、虚读的发生。
级别依次升高,效率依次降低。
MySQL:默认REPEATABLE READ
ORACLE:默认READ COMMITTED
MySQL:
select @@tx_isolation;//查看当前的隔离级别
set transaction isolation level 级别;// 设置当前的事务隔离级别
练习:read uncommitted;
时间 |
T1 |
T2 |
说明 |
t1 |
start transaction |
|
|
t2 |
select * from account where name='aaa'; 有1000块 |
|
|
t3 |
|
start transaction |
|
t4 |
|
update account set money=money+100 where name='aaa'; |
|
t5 |
select * from account where name='aaa'; 有1100块 |
|
读到了另外一个线程中未提交的数据:脏读 |
t6 |
|
commit; |
|
t7 |
select * from account where name='aaa'; 有1100块 |
|
读到了另外一个线程中提交的update数据:不可重复读 |
t8 |
select count(*) from account; 有3条记录 |
|
|
t9 |
|
insert into account values(4,'ddd',1000); |
|
t10 |
select count(*) from account; 有4条记录 |
|
读到了另外一个线程中提交的insert数据:虚读(幻读) |
t11 |
commit; |
|
|
|
|
|
|
//设置隔离级别
public class IsolationLevelDemo {
@Test
public void test1() throws Exception{
Connection conn = JdbcUtil.getConnection();
//一定要在开启事务前更改隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
// ....
conn.commit();
}
}