向数据表中插入Blob类型的数据
//向数据表customers中插入Blob类型的字段
public void testInsert() throws Exception{
Connection conn = JDBCUtil.getConnection();
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1,"达达");
ps.setObject(2,"123@163.com");
ps.setObject(3,"1992-09-08");
FileInputStream is = new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\bird.jpg"));
ps.setBlob(4,is);
ps.execute();
JDBCUtil.closeResource(conn,ps);
}
public void testQuery(){
Connection conn = null;
PreparedStatement ps = null;
InputStream is = null;
FileOutputStream fos = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
String sql = "select id,name,email,birth,photo from customers where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1,21);
rs = ps.executeQuery();
if (rs.next()){
//方式1:顺序不能改变
// int id = rs.getInt(1);
// String name = rs.getString(2);
// String email = rs.getString(3);
// Date birth = rs.getDate(4);
//方式2:
int id = rs.getInt("id");
String name =rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer cust = new Customer(id,name,email,birth);
System.out.println(cust);
//将Blob类型的字段下载下来,以文件的方式保存在本地
Blob photo = rs.getBlob("photo");
is = photo.getBinaryStream();
fos = new FileOutputStream("bird.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (is != null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
JDBCUtil.closeResource(conn,ps,rs);
}
}
如果指定了相关的Blob类型以后,还报错 xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数:max_allowed_packet=16M
批量插入数据的操作:
update、delete本身就具有批量操作的效果,此时的批量操作,主要是指批量插入,使用preparedStatement实现高效的批量插入
向goods表中插入2000条数据:
批量插入的方式:
方式1:耗时很久
public void testInsert1() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtil.getConnection();
String sql = "Insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1;i <= 20000;i++){
ps.setObject(1,"name_" + i);
ps.execute();
}
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
} catch (Exception e) {
e.printStackTrace();
}
JDBCUtil.closeResource(conn,ps);
}
方式2:耗时565
addBatch()、exexuteBatch()、clearBacth()
mysql服务器默认是关闭批处理的,我们需要通过一个参数,让Mysql开启批处理的支持,?rewriteBatchStatements=true 写在配置文件url的后面
使用更新的Mysql驱动:mysql-connector-java-5.1.37-bin.jar
public void testInsert2(){
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtil.getConnection();
String sql = "Insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1;i <= 20000;i++){
ps.setObject(1,"name_" + i);
//攒sql语句
ps.addBatch();
if (i % 500 == 0){
//执行bacth
ps.execute();
//清空batch
ps.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
} catch (Exception e) {
e.printStackTrace();
}
JDBCUtil.closeResource(conn,ps);
}
方式3:
@Test
//设置连接不运行自动提交数据
public void testInsert3(){
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtil.getConnection();
conn.setAutoCommit(false);
String sql = "Insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1;i <= 20000;i++){
ps.setObject(1,"name_" + i);
ps.addBatch();
if (i % 500 == 0){
ps.execute();
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
} catch (Exception e) {
e.printStackTrace();
}
JDBCUtil.closeResource(conn,ps);
}
数据库事务的问题引入:
数据一旦提交,就不可回滚
哪些操作会导致数据的自动提交?
DDL操作一旦执行,就会自动提交
DML默认情况下,一旦执行,就会自动提交,我们可以通过set autocommit = false的方式取消DML操作的自动提交
默认在关闭连接时,会自动的提交数据
考虑事务,数据修改的代码实现:
@Test
public void testUpdate() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
System.out.println(conn.getAutoCommit());
//取消数据的自动提交
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(conn,sql1,"AA");//之前写过的update()方法
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(conn,sql2,"BB");
System.out.println("转账成功");
//提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
//回滚数据
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
//主要针对于使用数据库连接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
JDBCUtil.closeResource(conn,null);
}
}
JDBC事务处理:
若此时Connection没有被关闭,还可能被重复利用,则需要恢复自动提交状态
数据库连接池:
JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由服务器实现。
多种开源的数据库连接池:
DBCP是Apache提高的数据库连接池。tomcat服务器自带dbcp数据库连接池,速度相对c3p0较快,但因自身存在BUG,hibernate3已不再提供使用。
C3P0是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以,hibernate官方推荐使用。
Druid是阿里提供的数据库连接池,集DBCP,C3P0,Proxool优点于一身的数据库连接池。
Apache-DBUtils实现CRUD操作:
common-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能
插入操作:
@Test
public void testInsert() throws Exception {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtil.getConnection1();
String sql = "insert into customers(name,email,birth)values(?,?,?)";
int insertCount = runner.update(conn,sql,"蔡徐坤","caixukun@163.com","1997-08-09");
System.out.println("添加了"+ insertCount + "条记录");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.closeResource(conn,null);
}
}
查询操作:
单条
//BeanHander:是ResultSetHandler接口的实现类,用于封装表中的一条记录
public void QueryTest() throws Exception {
QueryRunner runner = new QueryRunner();
Connection conn = JDBCUtil.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
Customer customer = runner.query(conn, sql, handler, 23);
}
多条查询:
//BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合
public void QueryTest2() throws Exception {
QueryRunner runner = new QueryRunner();
Connection conn = JDBCUtil.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
List<Customer> list = runner.query(conn, sql, handler, 23);
list.forEach(System.out::println);
}
以Map的形式返回
MapHandler handler = new MapHandler();
Map<String, Object> map =runner.query(conn,sql,handler,23);
System.out.println(map);
查询特殊值:
public void QueryTest4() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtil.getConnection3();
String sql = "select count(*) from customers";
ScalarHandler handler = new ScalarHandler();
Long count = (Long) runner.query(conn,sql,handler);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void QueryTest5() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtil.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>() {
@Override
public Customer handle(ResultSet rs) throws SQLException {
// System.out.println("handle");
// return null;
// return new Customer(12,"cheng","jack@163.com,new Date(5564646264L)");
if (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer customer = new Customer(id, name, email, birth);
return customer;
}
return null;
}
};
Customer customer = runner.query(conn, sql, handler, 23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.closeResource(conn,null);
}
}
}