JDBC
JDBC:java和数据库的连接,Sun公司定义的一套java操作数据库的接口规范。
快速入门
准备工作
- 数据库准备
create database mytestdb character set utf8; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `uid` varchar(50) NOT NULL, `username` varchar(20) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `name` varchar(20) DEFAULT NULL, `email` varchar(30) DEFAULT NULL, `telephone` varchar(20) DEFAULT NULL, `birthday` date DEFAULT NULL, `sex` varchar(10) DEFAULT NULL, `state` int(11) DEFAULT NULL, `code` varchar(64) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES ('10d27af0-7dd7-456c-ac81-bacd4833490d', 'root', '123456', '管理员', 'root@126.com', null, '2017-07-01', 'man', null, null); INSERT INTO `user` VALUES ('1be0290a-c300-4bc1-8f67-de061904e60e', 'zhangsan', '123', '张三', 'zhangsan@126.com', null, '2017-07-18', 'woman', null, null); INSERT INTO `user` VALUES ('3e663996-83ac-4cda-ad79-b15080553837', 'lisi', '123', '李四', 'lisi@126.com', null, '2017-07-18', 'man', null, null); INSERT INTO `user` VALUES ('5814301c-463e-4b66-9dcb-fc1ed7c29341', 'wangwu', '123', '王五', 'wangwu@126.com', null, '2017-07-11', 'woman', null, null); INSERT INTO `user` VALUES ('7e1927b6-67b4-4250-a01c-d054e730dd34', 'admin', '123456', 'Administror', 'admin@163.com', null, '2017-07-05', 'woman', null, null);
-
导入jar包
比如:mysql-connector-java-5.0.8-bin.jar统计user表的中记录数
/** * 快速入门 * 获取user表中所有的记录书 * @throws Exception */ @Test public void test01() throws Exception { // 1、注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2、 获取连接 String url = "jdbc:mysql://127.0.0.1:3306/mytestdb"; String user = "root"; String password = "123456"; Connection conn = DriverManager.getConnection(url, user, password); // 3、获取发送sql的对象 Statement statement = conn.createStatement(); // 4、执行sql,返回结果 String sql = "select count(*) from user"; ResultSet resultSet = statement.executeQuery(sql); // 5、处理结果 while (resultSet.next()){ int count = resultSet.getInt(1); System.out.println("user表中一共有"+count+"条数据"); } // 6、关闭资源 resultSet.close(); statement.close(); conn.close(); }
执行结果:user表中一共有5条数据
修改表中的数据
/** * 修改表的记录 */ @Test public void test02(){ Connection conn = null; Statement statement = null; try { // 1、注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2、 获取连接 String url = "jdbc:mysql://127.0.0.1:3306/mytestdb"; String user = "root"; String password = "123456"; conn = DriverManager.getConnection(url, user, password); // 3、获取发送sql的对象 statement = conn.createStatement(); // 4、执行sql,返回结果 String sql = "update user set name='哈哈' where uid='5814301c-463e-4b66-9dcb-fc1ed7c29341'"; int num = statement.executeUpdate(sql); // 5、处理结果 if (num > 0){ System.out.println("修改成功!"); }else{ System.out.println("修改失败!"); } } catch (Exception e) { e.printStackTrace(); }finally { // 6、关闭资源 try { if (statement != null){ statement.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (conn != null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
使用PreparedStatement,来方式sql注入的问题。
/** * 使用PreparedStatement来解决sql注入的问题 * 查询sex = woman的用户 */ @Test public void test03(){ Connection conn = null; PreparedStatement prepareStatement = null; ResultSet rs = null; try { // 1、注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2、 获取连接 String url = "jdbc:mysql://127.0.0.1:3306/mytestdb"; String user = "root"; String password = "123456"; conn = DriverManager.getConnection(url, user, password); // 3、获取发送sql的对象 String sql = "select * from user where sex=?"; prepareStatement = conn.prepareStatement(sql); // 4、执行sql,返回结果 prepareStatement.setString(1, "woman"); rs = prepareStatement.executeQuery(); // 5、处理结果 while (rs.next()){ System.out.println(rs.getString("username")+"==="+rs.getString("password")); } } catch (Exception e) { e.printStackTrace(); }finally { // 6、关闭资源 try { if (rs != null){ rs.close(); } } catch (SQLException e1) { e1.printStackTrace(); } try { if (prepareStatement != null){ prepareStatement.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (conn != null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
使用c3p0连接池:
-
配置文件,必须放在src目录下,名称为:c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mytestdb</property> <property name="user">root</property> <property name="password">123456</property> </default-config> <!-- This app is massive! --> <named-config name="store"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/store</property> <property name="user">root</property> <property name="password">123456</property> </named-config> </c3p0-config>
-
使用c3p0连接池完成查询
/** * 使用c3p0完成查询工作 */ @Test public void test04() throws Exception { // 创建连接池 ComboPooledDataSource dataSource = new ComboPooledDataSource(); // 从连接池中获取连接 Connection conn = dataSource.getConnection(); // 获取发送sql的对象 Statement statement = conn.createStatement(); // 执行sql,返回结果 String sql = "select count(*) from user"; ResultSet resultSet = statement.executeQuery(sql); // 处理结果 while (resultSet.next()) { int count = resultSet.getInt(1); System.out.println("user表中一共有" + count + "条数据"); } // 关闭资源 resultSet.close(); statement.close(); conn.close(); }
创建jdbc的工具类
public class JDBCUtils { private static ComboPooledDataSource ds = new ComboPooledDataSource(); private static ThreadLocal<Connection> tl = new ThreadLocal<>(); //返回连接池 public static DataSource getDataSource(){ return ds; } /** * 返回一个连接,此连接与当前线程绑定了 * 可以保证 此线程拿到的线程都是同一个 * @return * @throws Exception */ public static Connection getConnection() throws Exception { Connection conn = tl.get(); if (conn == null){ conn = ds.getConnection(); tl.set(conn); } return conn; } }
使用DBUtils来简化JDCB操作
/** * 使用DBUtils来统计user表中的记录数 */ @Test public void test05(){ // 利用工具类获取连接池,创建QueryRunner对象 QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select count(*) from user"; try { Number number = qr.query(sql, new ScalarHandler<Number>()); System.out.println("user表中共有"+number.intValue()+"条记录。"); } catch (SQLException e) { e.printStackTrace(); } /** * 这里不用释放连接,DBUtils会自动关闭,如果创建QueryRunner对象没有参数时,如下: * QueryRunner qr = new QueryRunner() * 这时,需要自己关闭连接 */ }
事务的特性(ACID)
- A:原子性:事务是一个整体,不可分割
- C:一致性: 事务执行前和执行后,数据库必须处于一致的状态;如果事务执行成功,数据库的所有变化都将发生变化;如果事务执行失败,数据库的变化都将回滚,回到原始状态
- I:隔离性: 多用户进行并发访问时,一个用户的事务,不能被其他用户的事务干扰,多个事务之间是互相隔离的。多个事务时事件是独立的,不能互相干扰
- D:持久性: 一旦事务提交,它对数据库的改变将是持久性的
如果不考虑事务的隔离性,将发生:脏读,不可重复度,幻读/虚读
- 脏读: 一个事务读取到其他事务未提交的数据
- 不可重复度: 一个事务多次读取表中的数据,结果不一样;读取了其它事务已经提交的数据(强调的数据被update)
- 幻读: 一个事务读取到了其他事务提交的数据(强调的是记录数的变化,insert,delete)
数据库的隔离级别
- read uncnmitted 读未提交 问题:脏读,不可重复读,幻读
- read cnmitted 读已提交 问题: 不可重复读,幻读 (oracle默认的级别)
- repeatable read 可重复读 问题: 幻读 (mysql默认的级别)
- serializable 串行化