将琴存诗
人生 可以不要那么 耀 ,只需要有 一个  平凡的梦想  足以 。—— loveincode -_^ RSS
Fork me on GitHub

JavaWeb 后端 <九> 之 JDBC加强

一、大结果集的分页(重点,难点)

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(练一遍)

降低与数据库的交互次数,提升执行效率
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();
	}
}

 

posted @ 2016-03-18 20:56  loveincode  阅读(406)  评论(0编辑  收藏  举报
最简单即最美
有了信仰,自己要坚持努力 2017.07.09 21:34