JDBC(MySQL)一周学习总结(二)
上一篇文章我们总结了获取数据库连接以及操作数据表的一些知识点,本篇将继续上次的文章给大家分享!
1. 上一篇文章我们可以对数据表进行增删改查的操作了,对与一些小项目的部分功能我们也足以胜任。但现在有一个需求是一个人下了一个订单,并将这个订单的下单时间等信息插入了订单表,并且其主键是自动生成主键值,当我们想要找到该用户买了哪些商品(商品表)时,则需要用订单 ID 去获取商品列表,此时就需要获得数据库自动生成的主键值(不针对于不自动生成主键的数据库,如 Oracle)。
取得数据库自动生成的主键值,使用重载的 prepareStatement(sql, flag) 方法使其生成自动生成的主键值,使用 getGennratedKeys() 获得自动生成的主键值的结果集,代码如下(具体方法可以在 API 中进行进一步的了解):
@Test
public void testGetKey() { Connection connection;
PreparedStatement preparedStatement; connection = JDBCTools.getConnection();
String sql = "INSERT INTO book (book_name, isbn, price, stock) VALUES (?, ?, ?, ?)";
try {
// 设置其可以返回自动生成的主键值
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, "R");
preparedStatement.setString(2, "10011");
preparedStatement.setInt(3, 220);
preparedStatement.setInt(4, 10); preparedStatement.executeUpdate();
// 获取自动生成的主键值,需要调用方法 getGeneratedKeys(),返回一个结果集,这个方法
ResultSet resultSet = preparedStatement.getGeneratedKeys(); if (resultSet.next()) {
System.out.println(resultSet.getObject(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
2. 处理 Blob 类型数据,如插入图片,读取图片的操作,往数据库中插入 BLOB 类型的数据必须使用 prepareStatement,因为插入 BLOB 类型的数据使用的 sql 语句无法拼写出来;下面是插入 Blob 型数据
@Test
public void testBlob() { Connection connection;
PreparedStatement preparedStatement; connection = JDBCTools.getConnection();
String sql = "INSERT INTO pic_blob (pic) VALUES ( ?)";
try {
preparedStatement = connection.prepareStatement(sql); File file = new File("C:\\Users\\lenovo\\Desktop\\key.png");
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 使用输入流填充参数
preparedStatement.setBlob(1, inputStream);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
插入 Blob 类型数据就肯定可以读取 Blbo 型数据,理解了上面的方法后就大概知道了读取需要使用 OutputStream,你可以先自己尝试一下如何去写,看有什么困难在看下面的代码:
@Test
public void testBlobGet() { Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null; connection = JDBCTools.getConnection();
String sql = "SELECT pic FROM pic_blob WHERE id=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1); resultSet = preparedStatement.executeQuery();
// 和 IO 那块一样,使用字节数组加快读取速度
byte[] buffer = new byte[1024];
int len; while (resultSet.next()) {
try {
Blob pic = resultSet.getBlob(1);
// 获取输入流
InputStream inputStream = pic.getBinaryStream();
// 将图片存到一个位置,通过输出流
OutputStream outputStream = new FileOutputStream("C:\\Users\\lenovo\\Desktop\\key2.png"); while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.close();
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(connection, preparedStatement, resultSet);
}
}
3. 数据库事务处理。简单的说几个对数据库的操作要么全都执行,要么全都不执行,需要保持一致性,Mysql 数据库默认的执行一个操作便会自动提交,为了处理事务我们必须设置数据库不是自动提交的,还有若每个对数据表的操作都是自己单独的连接,那么就无法保证事务,所以我们需要更改以前写的工具类,使其使用一个数据库连接,然后等所有操作结束之后我们再手动提交操作,若发生异常便进行回滚,具体代码如下:
@Test
public void testTransaction1() {
Connection connection = null;
try {
// 为下面的 update 方法传入一个统一的连接
connection = JDBCTools.getConnection();
// 关闭自动提交
connection.setAutoCommit(false);
String sql1 = "UPDATE book SET price = price - 500 WHERE id = 1";
update(connection, sql1);
// 制造异常检查事务的正确性
// int i = 2 / 0; String sql2 = "UPDATE book SET price = price + 500 WhERE id = 2";
update(connection, sql2);
// 执行完毕,手动提交
connection.commit();
} catch (SQLException e) {
try {
// 如果发生异常将其进行回滚
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
} // 更改后的 update 方法使用的 connection 不再是在其内部每次调用方法获取新的连接,而是传入一个连接使其统一
public void update(Connection connection, String sql, Object... args) {
PreparedStatement preparedStatement = null; try {
preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
} preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(null, preparedStatement, null);
}
}
如果数据库中同时运行多个事务,若没有设置合适隔离级别将会出现各种并发问题:脏读,不可重复读,幻读等问题。将数据库隔离级别设置的越高数据的一致性就越高但并发性也就越差。
Oracle 数据库支持两种事务隔离级别,READ_COMMITED(读已提交),SERIALIZABLE(串行化),其默认的隔离级别是 READ_COMMITED
MySQL 数据库支持四种事务隔离级别,默认的隔离级别是 REPEATBLE READ(读未提交)。大多数情况下我们设置为 READ_COMMITED 最为合适,我们可以使用 connection.setTransactionIsolation(); 来设置数据库的隔离级别
4. 我们在这之前所使用的数据库连接是每次从数据库中获取一个使用完毕就将其放入数据库,这样的操作比较浪费,所以也就有了数据库连接池,其基本思想: 为数据库连接建立一个缓冲池,预先放入一定数量的连接,需要时从缓冲池中取出一个,使用完毕放入,当使用的时候没有多余的连接时需要等待。这样就节省了很多的时间,下面是使用 c3p0 连接池获取数据库连接的代码:
@Test
public void testC3p0() {
// 在使用之前需要导入对应的 jar 包文件
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///sh_db");
dataSource.setUser("root");
dataSource.setPassword("zy961029"); System.out.println(dataSource.getConnection());
} catch (PropertyVetoException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
和之前的一样,我们也需要将上面的方法加以配置文件的处理(程序中的 helloc3p0 是配置文件中所配置 <name-config name="helloC3p0"> )
@Test
public void testC3p0Config() {
// 注意 jar 包的版本问题,0.9.2 之前的不支持下面的写法
ComboPooledDataSource dataSource = new ComboPooledDataSource("helloC3p0");
try {
Connection connection = dataSource.getConnection();
System.out.println(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<named-config name="helloC3p0">
<property name="user">root</property>
<property name="password">zy961029</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///sh_db</property> <property name="maxStatements">1</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
C3p0-congfig.xml
5. 使用 DBUtils,commons-dbutils 是 Apache 组织提供的一个开源 JDBC 工具类,它是对 JDBC 的简单封装,学习成本低,并且简化了代码,不影响代码的性能
使用 DBUTils 进行简单的增删改查功能(可以在包内的 API 中进行对相应的类进行了解 )
QueryRunner 类简化了 SQL 查询,与 ResultSetHandler 组合可以完成大部分的数据操作,减少编码量
package com.jdbc.dao.my.dbutils; import com.jdbc.dao.my.first.test.JDBCTools;
import com.jdbc.dao.my.first.test.SH_DB;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.*;
import org.junit.Test; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; /**
* Created by shkstart on 2017/11/02.
*/
public class DBUtilsTest { // C3p0 获取数据库连接
@Test
public void testGetConnection() {
// 更新工具类中获取数据库连接的方法,使用 c3p0 数据库连接
Connection connection = JDBCTools.getConnection();
System.out.println(connection);
} // 使用 QueryRunner 删除数据 --> DBUtils
@Test
public void testUpdate() {
QueryRunner queryRunner = new QueryRunner();
Connection connection;
connection = JDBCTools.getConnection();
// String sql = "DELETE FROM book WHERE id=?";
String sql = "INSERT INTO book (book_name, isbn, price, stock) values(?, ?, ?, ?)";
try {
queryRunner.update(connection, sql, "C#", "1008", 120, 40);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(connection, null, null);
}
} // 将查询到的所有数据打印出来,
@Test
public void resultSetHandler() {
QueryRunner queryRunner = new QueryRunner();
Connection connection;
final List<SH_DB> sh_dbs = new ArrayList<SH_DB>();
connection = JDBCTools.getConnection();
String sql = "SELECT book_name bookName, isbn, price, stock FROM book";
try {
queryRunner.query(connection, sql, new ResultSetHandler<Object>() {
@Override
public Object handle(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
String bookName = resultSet.getString(1);
String isbn = resultSet.getString(2);
int price = resultSet.getInt(3);
int stock = resultSet.getInt(4);
SH_DB sh_db = new SH_DB(bookName, isbn, price, stock);
sh_dbs.add(sh_db);
}
return sh_dbs;
}
}); System.out.println(sh_dbs);
} catch (SQLException e) {
e.printStackTrace();
}
} // 把结果集的第一条记录转为创建 BeanHandler 对象时传入的对象
@Test
public void testBeanHandler() {
Connection connection;
QueryRunner queryRunner = new QueryRunner();
connection = JDBCTools.getConnection(); String sql = "SELECT * FROM BOOK";
try {
SH_DB sh_db = queryRunner.query(connection, sql, new BeanHandler<SH_DB>(SH_DB.class));
System.out.println(sh_db);
} catch (SQLException e) {
e.printStackTrace();
}
} // 返回查询结果的 list 结果集,其中查询语句必须使用表对应 bean 的列的别名
// BeanHandler 也一样
@Test
public void testBeanListHandler() {
Connection connection = JDBCTools.getConnection();
String sql = "SELECT book_name bookName, isbn, price, stock FROM book";
QueryRunner queryRunner = new QueryRunner(); try {
List<SH_DB> sh_dbs = (List<SH_DB>) queryRunner.query(connection, sql, new BeanListHandler(SH_DB.class));
System.out.println(sh_dbs);
} catch (SQLException e) {
e.printStackTrace();
}
} // 将查询结果的第一行存放进一个 map 中,键位 列名,而不是列的别名, 值为 所对应的值
@Test
public void testMapHandler() {
Connection connection = JDBCTools.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "SELECT book_name bookName, isbn, price, stock from book " +
"where id = ?"; try {
Map<String, Object> map = queryRunner.query(connection, sql, new MapHandler(), 5);
System.out.println(map); for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
} catch (SQLException e) {
e.printStackTrace();
}
} // 将查询结果的存入一个 List,其 list 的元素为一个 map,对应一列
@Test
public void testListHandler() {
Connection connection = JDBCTools.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "SELECT book_name bookName, isbn, price, stock from book"; try {
List<Map<String, Object>> listMap = queryRunner.query(connection, sql, new MapListHandler());
System.out.println(listMap);
} catch (SQLException e) {
e.printStackTrace();
}
} // 将查询的一个结果放入 object 返回,比如返回记录数,返回某一列的值,如果 sql 语句是返回多条记录的
// 那么 ScalarHandler 将返回的是第一列的值
@Test
public void testScalarHandler() {
Connection connection = JDBCTools.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "SELECT COUNT(*) FROM book"; try {
Object object = queryRunner.query(connection, sql, new ScalarHandler());
System.out.println(object);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上一篇加上本篇就是上一周所学习的东西,太多,总结起来也挺费力的如果有什么错误还望指出,谢谢!!!
JDBC(MySQL)一周学习总结(二)的更多相关文章
- 【笔记】MySQL的基础学习(二)
[笔记]MySQL的基础学习(二) MySQL 老男孩 一 视图 视图其实就是给表起个别名 1.创建视图 格式:CREATE VIEW 视图名称 AS SQL语句 CREATE VIEW v1 AS ...
- mysql 复习与学习(二)数据库及表结构的创建删除
mysql -h localhost -uroot -p123456 //连接数据库 show databases; //查看数据库 create database if not exists db_ ...
- JDBC(MySQL)一周学习总结(一)
一周过去了,我在这分享一下这一周来学习 JDBC 的知识,同时也希望可以帮到别人! 首先我们从获取 JDBC 连接开始 Driver(每个驱动程序类必须实现的接口) 获取数据库连接需要配置数据库连接信 ...
- Java基础学习笔记二十六 JDBC
什么是JDBC JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库.原来我们操作数据库是在控制台使用SQL语句来操作数据库,J ...
- JDBC+MYSQL初始学习
JDBC+MYSQL初始学习 一.学习准备 Eclipse 开发工具 + mysql数据库+navicat 数据库连接工具 Mysql的数据库连接驱动jar包 + testing测试集成+mave ...
- JDBC学习笔记二
JDBC学习笔记二 4.execute()方法执行SQL语句 execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象 ...
- 201521123061 《Java程序设计》第十二周学习总结
201521123061 <Java程序设计>第十二周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对 ...
- 201521123072《java程序设计》第十二周学习总结
201521123072<java程序设计>第十二周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象 ...
- 201521123038 《Java程序设计》 第十二周学习总结
201521123038 <Java程序设计> 第十二周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student ...
随机推荐
- Ensemble Learning: Bootstrap aggregating (Bagging) & Boosting & Stacked generalization (Stacking)
Booststrap aggregating (有些地方译作:引导聚集),也就是通常为大家所熟知的bagging.在维基上被定义为一种提升机器学习算法稳定性和准确性的元算法,常用于统计分类和回归中. ...
- tomcat部署项目的一点心得
打包方式 eclipse 右键项目Export 选择WAR file 在选择将打包好的war 包存放的位置 放到tomcat中运行 : 首先将war包fang放到解压的tomcat中的weba ...
- Vue路由vue-router
前面的话 在Web开发中,路由是指根据URL分配到对应的处理程序.对于大多数单页面应用,都推荐使用官方支持的vue-router.Vue-router通过管理URL,实现URL和组件的对应,以及通过U ...
- 分享基于分布式Http长连接框架
第一次在博客园写文章,长期以来只是潜水中.本着不只索取,而要奉献的精神,随笔文章之. 现贡献一套长连接的框架.如下特性: 1:发布者可异步发送消息,消息如果发送失败,可重试发送,重试次数基于配置,消息 ...
- 【BZOJ】2190 [SDOI2008]仪仗队(欧拉函数)
Description 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是 ...
- 石子合并(NOI1995)
石子合并(NOI1995) 时间限制: 1 Sec 内存限制: 128 MB提交: 90 解决: 48[提交][状态][讨论版] 题目描述 在操场上沿一直线排列着 n堆石子.现要将石子有次序地合并 ...
- 802.1Q VLAN技术原理
文章出处:http://hi.baidu.com/x278384/item/d56b0edfd4f56a4eddf9be79 在数据通信和宽带接入设备里,只要涉及到二层技术的,就会遇到VLAN.而且, ...
- python检查IP地址正确性
一.自动动手,丰衣足食 #encoding=utf-8 import os,sys def check_ip(ipaddr): addr = ipaddr.strip().split('.') #切割 ...
- 远程连接MySQL,防火墙阻止访问,解决方法
远程连接MySQL,防火墙阻止访问,解决方法 xp/2003添加防火墙例外端口 打开防火墙,选择例外选项卡,添加端口 名称:mysqlport 端口号:3306 选中TCP win7添加防火墙例外 ...
- mac 通过brew安装php70 +php-fpm+ phalcon3.0.3
安装php7.0.15 brew install homebrew/php/php70 brew install homebrew/php/php70-mcrypt brew install home ...