1 jdbc入门
1.1 之前操作数据
1)通过mysql的客户端工具,登录数据库服务器 (mysql -u root -p 密码)
2)编写sql语句
3)发送sql语句到数据库服务器执行
1.2 什么是jdbc?
使用java代码(程序)发送sql语句的技术,就是jdbc技术!!!!
1.3 使用jdbc发送sql前提
登录数据库服务器(连接数据库服务器)
数据库的IP地址
端口
数据库用户名
密码
/** * jdbc连接数据库 * @author APPle * */ public class Demo1 { //连接数据库的URL private String url = "jdbc:mysql://localhost:3306/day17"; // jdbc协议:数据库子协议:主机:端口/连接的数据库 // private String user = "root";//用户名 private String password = "root";//密码 /** * 第一种方法 * @throws Exception */ @Test public void test1() throws Exception{ //1.创建驱动程序类对象 Driver driver = new com.mysql.jdbc.Driver(); //新版本 //Driver driver = new org.gjt.mm.mysql.Driver(); //旧版本 //设置用户名和密码 Properties props = new Properties(); props.setProperty("user", user); props.setProperty("password", password); //2.连接数据库,返回连接对象 Connection conn = driver.connect(url, props); System.out.println(conn); } /** * 使用驱动管理器类连接数据库(注册了两次,没必要) * @throws Exception */ @Test public void test2() throws Exception{ Driver driver = new com.mysql.jdbc.Driver(); //Driver driver2 = new com.oracle.jdbc.Driver(); //1.注册驱动程序(可以注册多个驱动程序) DriverManager.registerDriver(driver); //DriverManager.registerDriver(driver2); //2.连接到具体的数据库 Connection conn = DriverManager.getConnection(url, user, password); System.out.println(conn); } /** * (推荐使用这种方式连接数据库) * 推荐使用加载驱动程序类 来 注册驱动程序 * @throws Exception */ @Test public void test3() throws Exception{ //Driver driver = new com.mysql.jdbc.Driver(); //通过得到字节码对象的方式加载静态代码块,从而注册驱动程序 Class.forName("com.mysql.jdbc.Driver"); //Driver driver2 = new com.oracle.jdbc.Driver(); //1.注册驱动程序(可以注册多个驱动程序) //DriverManager.registerDriver(driver); //DriverManager.registerDriver(driver2); //2.连接到具体的数据库 Connection conn = DriverManager.getConnection(url, user, password); System.out.println(conn); } } |
1.4 JDBC接口核心的API
java.sql.* 和 javax.sql.*
|- Driver接口: 表示java驱动程序接口。所有的具体的数据库厂商要来实现此接口。
|- connect(url, properties): 连接数据库的方法。
url: 连接数据库的URL
URL语法: jdbc协议:数据库子协议://主机:端口/数据库
user: 数据库的用户名
password: 数据库用户密码
|- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序
|-registerDriver(driver) : 注册驱动类对象
|-Connection getConnection(url,user,password); 获取连接对象
|- Connection接口: 表示java程序和数据库的连接对象。
|- Statement createStatement() : 创建Statement对象
|- PreparedStatement prepareStatement(String sql) 创建PreparedStatement对象
|- CallableStatement prepareCall(String sql) 创建CallableStatement对象
|- Statement接口: 用于执行静态的sql语句
|- int executeUpdate(String sql) : 执行静态的更新sql语句(DDL,DML)
|- ResultSet executeQuery(String sql) :执行的静态的查询sql语句(DQL)
|-PreparedStatement接口:用于执行预编译sql语句
|- int executeUpdate() : 执行预编译的更新sql语句(DDL,DML)
|-ResultSet executeQuery() : 执行预编译的查询sql语句(DQL)
|-CallableStatement接口:用于执行存储过程的sql语句(call xxx)
|-ResultSet executeQuery() : 调用存储过程的方法
|- ResultSet接口:用于封装查询出来的数据
|- boolean next() : 将光标移动到下一行
|-getXX() : 获取列的值
2 使用Statement执行sql语句
2.1 执行DDL语句
/** * 执行DDL语句(创建表) */ @Test public void test1(){ Statement stmt = null; Connection conn = null; try { //1.驱动注册程序 Class.forName("com.mysql.jdbc.Driver"); //2.获取连接对象 conn = DriverManager.getConnection(url, user, password); //3.创建Statement stmt = conn.createStatement(); //4.准备sql String sql = "CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),gender VARCHAR(2))"; //5.发送sql语句,执行sql语句,得到返回结果 int count = stmt.executeUpdate(sql); //6.输出 System.out.println("影响了"+count+"行!"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally{ //7.关闭连接(顺序:后打开的先关闭) if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } |
2.2 执行DML语句
/** * 使用Statement执行DML语句 * @author APPle * */ public class Demo2 { private String url = "jdbc:mysql://localhost:3306/day17"; private String user = "root"; private String password = "root"; /** * 增加 */ @Test public void testInsert(){ Connection conn = null; Statement stmt = null; try { //通过工具类获取连接对象 conn = JdbcUtil.getConnection(); //3.创建Statement对象 stmt = conn.createStatement(); //4.sql语句 String sql = "INSERT INTO student(NAME,gender) VALUES('李四','女')"; //5.执行sql int count = stmt.executeUpdate(sql); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally{ //关闭资源 /*if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); }*/ JdbcUtil.close(conn, stmt); } } /** * 修改 */ @Test public void testUpdate(){ Connection conn = null; Statement stmt = null; //模拟用户输入 String name = "陈六"; int id = 3; try { /*//1.注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获取连接对象 conn = DriverManager.getConnection(url, user, password);*/ //通过工具类获取连接对象 conn = JdbcUtil.getConnection(); //3.创建Statement对象 stmt = conn.createStatement(); //4.sql语句 String sql = "UPDATE student SET NAME='"+name+"' WHERE id="+id+""; System.out.println(sql); //5.执行sql int count = stmt.executeUpdate(sql); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally{ //关闭资源 /*if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); }*/ JdbcUtil.close(conn, stmt); } } /** * 删除 */ @Test public void testDelete(){ Connection conn = null; Statement stmt = null; //模拟用户输入 int id = 3; try { /*//1.注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获取连接对象 conn = DriverManager.getConnection(url, user, password);*/ //通过工具类获取连接对象 conn = JdbcUtil.getConnection(); //3.创建Statement对象 stmt = conn.createStatement(); //4.sql语句 String sql = "DELETE FROM student WHERE id="+id+""; System.out.println(sql); //5.执行sql int count = stmt.executeUpdate(sql); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally{ //关闭资源 /*if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); }*/ JdbcUtil.close(conn, stmt); } } } |
3.3 执行DQL语句
/** * 使用Statement执行DQL语句(查询操作) * @author APPle */ public class Demo3 { @Test public void test1(){ Connection conn = null; Statement stmt = null; try{ //获取连接 conn = JdbcUtil.getConnection(); //创建Statement stmt = conn.createStatement(); //准备sql String sql = "SELECT * FROM student"; //执行sql ResultSet rs = stmt.executeQuery(sql); //移动光标 /*boolean flag = rs.next(); flag = rs.next(); flag = rs.next(); if(flag){ //取出列值 //索引 int id = rs.getInt(1); String name = rs.getString(2); String gender = rs.getString(3); System.out.println(id+","+name+","+gender); //列名称 int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+","+name+","+gender); }*/ //遍历结果 while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+","+name+","+gender); } }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); }finally{ JdbcUtil.close(conn, stmt); } } } |
4 使用PreparedStatement执行sql语句
public class Demo1 { /** * 增加 */ @Test public void testInsert() { Connection conn = null; PreparedStatement stmt = null; try { //1.获取连接 conn = JdbcUtil.getConnection(); //2.准备预编译的sql String sql = "INSERT INTO student(NAME,gender) VALUES(?,?)"; //?表示一个参数的占位符 //3.执行预编译sql语句(检查语法) stmt = conn.prepareStatement(sql); //4.设置参数值 /** * 参数一: 参数位置 从1开始 */ stmt.setString(1, "李四"); stmt.setString(2, "男"); //5.发送参数,执行sql int count = stmt.executeUpdate(); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 修改 */ @Test public void testUpdate() { Connection conn = null; PreparedStatement stmt = null; try { //1.获取连接 conn = JdbcUtil.getConnection(); //2.准备预编译的sql String sql = "UPDATE student SET NAME=? WHERE id=?"; //?表示一个参数的占位符 //3.执行预编译sql语句(检查语法) stmt = conn.prepareStatement(sql); //4.设置参数值 /** * 参数一: 参数位置 从1开始 */ stmt.setString(1, "王五"); stmt.setInt(2, 9); //5.发送参数,执行sql int count = stmt.executeUpdate(); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 删除 */ @Test public void testDelete() { Connection conn = null; PreparedStatement stmt = null; try { //1.获取连接 conn = JdbcUtil.getConnection(); //2.准备预编译的sql String sql = "DELETE FROM student WHERE id=?"; //?表示一个参数的占位符 //3.执行预编译sql语句(检查语法) stmt = conn.prepareStatement(sql); //4.设置参数值 /** * 参数一: 参数位置 从1开始 */ stmt.setInt(1, 9); //5.发送参数,执行sql int count = stmt.executeUpdate(); System.out.println("影响了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 查询 */ @Test public void testQuery() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { //1.获取连接 conn = JdbcUtil.getConnection(); //2.准备预编译的sql String sql = "SELECT * FROM student"; //3.预编译 stmt = conn.prepareStatement(sql); //4.执行sql rs = stmt.executeQuery(); //5.遍历rs while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+","+name+","+gender); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { //关闭资源 JdbcUtil.close(conn,stmt,rs); } } } |
PreparedStatement vs Statment
1)语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
2)效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
3)安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。
推荐使用PreparedStatement
4 CallableStatement执行存储过程
/** * 使用CablleStatement调用存储过程 * @author APPle * */ public class Demo1 { /** * 调用带有输入参数的存储过程 * CALL pro_findById(4); */ @Test public void test1(){ Connection conn = null; CallableStatement stmt = null; ResultSet rs = null; try { //获取连接 conn = JdbcUtil.getConnection(); //准备sql String sql = "CALL pro_findById(?)"; //可以执行预编译的sql //预编译 stmt = conn.prepareCall(sql); //设置输入参数 stmt.setInt(1, 6); //发送参数 rs = stmt.executeQuery(); //注意: 所有调用存储过程的sql语句都是使用executeQuery方法执行!!! //遍历结果 while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+","+name+","+gender); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } /** * 执行带有输出参数的存储过程 * CALL pro_findById2(5,@NAME); */ @Test public void test2(){ Connection conn = null; CallableStatement stmt = null; ResultSet rs = null; try { //获取连接 conn = JdbcUtil.getConnection(); //准备sql String sql = "CALL pro_findById2(?,?)"; //第一个?是输入参数,第二个?是输出参数 //预编译 stmt = conn.prepareCall(sql); //设置输入参数 stmt.setInt(1, 6); //设置输出参数(注册输出参数) /** * 参数一: 参数位置 * 参数二: 存储过程中的输出参数的jdbc类型 VARCHAR(20) */ stmt.registerOutParameter(2, java.sql.Types.VARCHAR); //发送参数,执行 stmt.executeQuery(); //结果不是返回到结果集中,而是返回到输出参数中 //得到输出参数的值 /** * 索引值: 预编译sql中的输出参数的位置 */ String result = stmt.getString(2); //getXX方法专门用于获取存储过程中的输出参数 System.out.println(result); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } } |
5. 预编译sql处理(防止sql注入)
-- 创建数据库 CREATE DATABASE jdbc_demo DEFAULT CHARACTER SET utf8;i -- 创建表 USE jdbc_demo; CREATE TABLE admin( id INT PRIMARY KEY AUTO_INCREMENT, userName VARCHAR(20), pwd VARCHAR(20) ) |
|--Statement 执行SQL命令
|-- CallableStatement, 执行存储过程
|-- PreparedStatement 预编译SQL语句执行
使用预编译SQL语句的命令对象,好处:
1. 避免了频繁sql拼接 (可以使用占位符)
2. 可以防止sql注入
登陆模块,
输入用户名,密码!
注意,
要避免用户输入的恶意密码!
public class App { // 连接参数 //private String url = "jdbc:mysql://localhost:3306/jdbc_demo"; private String url = "jdbc:mysql:///jdbc_demo"; private String user = "root"; private String password = "root"; private Connection con; private Statement stmt; private PreparedStatement pstmt; private ResultSet rs; // 1. 没有使用防止sql注入的案例 @Test public void testLogin() { // 1.0 模拟登陆的用户名,密码 String userName = "tom"; //String pwd = "8881"; String pwd = " ' or 1=1 -- "; // SQL语句 String sql = "select * from admin where userName='"+userName+"' and pwd='"+pwd+"' "; System.out.println(sql); try { // 1.1 加载驱动,创建连接 Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection(url, user, password); // 1.2 创建stmt对象 stmt = con.createStatement(); // 1.3 执行查询 rs = stmt.executeQuery(sql); // 业务判断 if (rs.next()) { System.out.println("登陆成功, 编号:" + rs.getInt("id")); } } catch (Exception e) { e.printStackTrace(); } finally { // 1.4 关闭 try { rs.close(); stmt.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } } } // 2. 使用PreparedStatement, 防止sql注入 @Test public void testLogin2() { // 1.0 模拟登陆的用户名,密码 String userName = "tom"; //String pwd = "8881"; String pwd = " ' or 1=1 -- "; // SQL语句 String sql = "select * from admin where userName=? and pwd=? "; try { // 1.1 加载驱动,创建连接 Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection(url, user, password); // 1.2 创建pstmt对象 pstmt = con.prepareStatement(sql); // 对sql语句预编译 // 设置占位符值 pstmt.setString(1, userName); pstmt.setString(2, pwd); // 1.3 执行 rs = pstmt.executeQuery(); if (rs.next()) { System.out.println("登陆成功," + rs.getInt("id")); } } catch (Exception e) { e.printStackTrace(); } finally { // 1.4 关闭 try { rs.close(); pstmt.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } } } } |
6. 存储过程调用
-- 存储过程 -- 定义分隔符 DELIMITER $$ CREATE PROCEDURE proc_login() BEGIN SELECT * FROM admin; END $$ -- 调用 CALL proc_login; |
public class App_call { // 全局参数 private Connection con; private Statement stmt; private PreparedStatement pstmt; private CallableStatement cstmt; // 存储过程 private ResultSet rs; // 程序中调用存储过程 @Test public void testCall() throws Exception { try { //1 . 创建连接 con = JdbcUtil.getConnection(); //2. 创建执行存储过程的stmt对象 CallableStatement cstmt = con.prepareCall("CALL proc_login"); //3. 执行(存储过程) rs = cstmt.executeQuery(); // 遍历结果,测试 if (rs.next()) { String name = rs.getString("userName"); String pwd = rs.getString("pwd"); // 测试 System.out.println(name + pwd); } } catch (Exception e) { e.printStackTrace(); } } } |
7. 批处理
很多时候,需要批量执行sql语句!
需求:批量保存信息!
设计:
AdminDao
Public void save(List<Admin list){ // 目前用这种方式
// 循环
// 保存 (批量保存)
}
Public void save(Admin admin ){
// 循环
// 保存
}
技术:
|-- Statement
批处理相关方法
void addBatch(String sql) 添加批处理
void clearBatch() 清空批处理
int[] executeBatch() 执行批处理
实现:
Admin.java 实体类封装数据
AdminDao.java 封装所有的与数据库的操作
App.java 测试
public class Admin { private String userName; private String pwd; |
public class App { // 测试批处理操作 @Test public void testBatch() throws Exception { // 模拟数据 List<Admin> list = new ArrayList<Admin>(); for (int i=1; i<21; i++) { Admin admin = new Admin(); admin.setUserName("Jack" + i); admin.setPwd("888" + i); list.add(admin); } // 保存 AdminDao dao = new AdminDao(); dao.save(list); } } |
// 封装所有的与数据库的操作 public class AdminDao { // 全局参数 private Connection con; private PreparedStatement pstmt; private ResultSet rs; // 批量保存管理员 public void save(List<Admin> list) { // SQL String sql = "INSERT INTO admin(userName,pwd) values(?,?)"; try { // 获取连接 con = JdbcUtil.getConnection(); // 创建stmt pstmt = con.prepareStatement(sql); // 【预编译SQL语句】 for (int i=0; i<list.size(); i++) { Admin admin = list.get(i); // 设置参数 pstmt.setString(1, admin.getUserName()); pstmt.setString(2, admin.getPwd()); // 添加批处理 pstmt.addBatch(); // 【不需要传入SQL】 // 测试:每5条执行一次批处理 if (i % 5 == 0) { // 批量执行 pstmt.executeBatch(); // 清空批处理 pstmt.clearBatch(); } } // 批量执行 pstmt.executeBatch(); // 清空批处理 pstmt.clearBatch(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, rs); } } } |
8. 插入数据,获取自增长值
ü 需求:
李俊杰 18
张相 19
如何设计数据库?
编号 员工姓名 年龄 部门
01 李俊杰 18 开发部
02 张三 19 开发部’
思考:
如何减少数据冗余?
à 设置外键约束
所以,
编号 员工姓名 年龄 部门
01 李俊杰 18 1
02 张三 19 1
部门编号 部门名称
1 开发部
部门与员工,
一对多的关系
ü 设计数据库:
员工表 (外键表) 【员工表有一个外键字段,引用了部门表的主键】
部门表(主键表)
ü 编码总体思路:
保存员工及其对应的部门!
步骤:
1. 先保存部门
2. 再得到部门主键,再保存员工
开发具体步骤:
1. 设计javabean
2. 设计dao
3. 测试
部门 CREATE TABLE dept( deptId INT PRIMARY KEY AUTO_INCREMENT, deptName VARCHAR(20) ); -- 员工 CREATE TABLE employee( empId INT PRIMARY KEY AUTO_INCREMENT, empName VARCHAR(20), dept_id INT -- 外键字段 ); -- 给员工表添加外键约束 ALTER TABLE employee ADD CONSTRAINT FK_employee_dept_deptId FOREIGN KEY(dept_id) REFERENCES dept(deptId) ; |
public class EmpDao { private Connection con; private PreparedStatement pstmt; private ResultSet rs; // 保存员工,同时保存关联的部门 public void save(Employee emp){ // 保存部门 String sql_dept = "insert into dept(deptName) values(?)"; // 保存员工 String sql_emp = "INSERT INTO employee (empName,dept_id) VALUES (?,?)"; // 部门id int deptId = 0; try { // 连接 con = JdbcUtil.getConnection(); /*****保存部门,获取自增长*******/ // 【一、需要指定返回自增长标记】 pstmt = con.prepareStatement(sql_dept,Statement.RETURN_GENERATED_KEYS); // 设置参数 pstmt.setString(1, emp.getDept().getDeptName()); // 执行 pstmt.executeUpdate(); // 【二、获取上面保存的部门子增长的主键】 rs = pstmt.getGeneratedKeys(); // 得到返回的自增长字段 if (rs.next()) { deptId = rs.getInt(1); } /*****保存员工*********/ pstmt = con.prepareStatement(sql_emp); // 设置参数 pstmt.setString(1, emp.getEmpName()); pstmt.setInt(2, deptId); pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, rs); } } } |
9. 事务
基本概念:
事务使指一组最小逻辑操作单元,里面有多个操作组成。 组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。
事务ACID特性
l 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
l 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
l 隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
l 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
事务的特性:
原子性,是一个最小逻辑操作单元 !
一致性,事务过程中,数据处于一致状态。
持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。
隔离性, 事务与事务之间是隔离的。
案例
需求: 张三给李四转账
设计: 账户表
技术:
|-- Connection
void setAutoCommit(boolean autoCommit) ; 设置事务是否自动提交
如果设置为false,表示手动提交事务。
void commit() (); 手动提交事务
void rollback() ; 回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)
Savepoint setSavepoint(String name)
代码:
-- 账户表 CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, accountName VARCHAR(20), money DOUBLE ); -- 转账 UPDATE account SET money=money-1000 WHERE accountName='张三'; UPDATE account SET money=money+1000 WHERE accountName='李四'; |
public class AccountDao { // 全局参数 private Connection con; private PreparedStatement pstmt; // 1. 转账,没有使用事务 public void trans1() { String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';"; String sql_ls = "UPDATE account SET money=money+1000 WHERE accountName='李四';"; try { con = JdbcUtil.getConnection(); // 默认开启的隐士事务 con.setAutoCommit(true); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, null); } } // 2. 转账,使用事务 public void trans2() { String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';"; String sql_ls = "UPDATE1 account SET money=money+1000 WHERE accountName='李四';"; try { con = JdbcUtil.getConnection(); // 默认开启的隐士事务 // 一、设置事务为手动提交 con.setAutoCommit(false); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate(); } catch (Exception e) { try { // 二、 出现异常,需要回滚事务 con.rollback(); } catch (SQLException e1) { } e.printStackTrace(); } finally { try { // 三、所有的操作执行成功, 提交事务 con.commit(); JdbcUtil.closeAll(con, pstmt, null); } catch (SQLException e) { } } } // 3. 转账,使用事务, 回滚到指定的代码段 public void trans() { // 定义个标记 Savepoint sp = null; // 第一次转账 String sql_zs1 = "UPDATE account SET money=money-1000 WHERE accountName='张三';"; String sql_ls1 = "UPDATE account SET money=money+1000 WHERE accountName='李四';"; // 第二次转账 String sql_zs2 = "UPDATE account SET money=money-500 WHERE accountName='张三';"; String sql_ls2 = "UPDATE1 account SET money=money+500 WHERE accountName='李四';"; try { con = JdbcUtil.getConnection(); // 默认开启的隐士事务 con.setAutoCommit(false); // 设置事务手动提交 /*** 第一次转账 ***/ pstmt = con.prepareStatement(sql_zs1); pstmt.executeUpdate(); pstmt = con.prepareStatement(sql_ls1); pstmt.executeUpdate(); // 回滚到这个位置? sp = con.setSavepoint(); /*** 第二次转账 ***/ pstmt = con.prepareStatement(sql_zs2); pstmt.executeUpdate(); pstmt = con.prepareStatement(sql_ls2); pstmt.executeUpdate(); } catch (Exception e) { try { // 回滚 (回滚到指定的代码段) con.rollback(sp); } catch (SQLException e1) { } e.printStackTrace(); } finally { try { // 提交 con.commit(); } catch (SQLException e) { } JdbcUtil.closeAll(con, pstmt, null); } } } |
10. Jdbc中大文本类型的处理
Oracle中大文本数据类型,
Clob 长文本类型 (MySQL中不支持,使用的是text)
Blob 二进制类型
MySQL数据库,
Text 长文本类型
Blob 二进制类型
需求: jdbc中操作长文本数据。
设计: 测试表
编码:
保存大文本数据类型
读取大文本数据类型
保存二进制数据
读取二进制数据
-- 测试大数据类型 CREATE TABLE test( id INT PRIMARY KEY AUTO_INCREMENT, content LONGTEXT, img LONGBLOB ); |
Text: |
public class App_text { // 全局参数 private Connection con; private Statement stmt; private PreparedStatement pstmt; private ResultSet rs; @Test // 1. 保存大文本数据类型 ( 写longtext) public void testSaveText() { String sql = "insert into test(content) values(?)"; try { // 连接 con = JdbcUtil.getConnection(); // pstmt 对象 pstmt = con.prepareStatement(sql); // 设置参数 // 先获取文件路径 String path = App_text.class.getResource("tips.txt").getPath(); FileReader reader = new FileReader(new File(path)); pstmt.setCharacterStream(1, reader); // 执行sql pstmt.executeUpdate(); // 关闭 reader.close(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, null); } } @Test // 2. 读取大文本数据类型 ( 读longtext) public void testGetAsText() { String sql = "select * from test;"; try { // 连接 con = JdbcUtil.getConnection(); // pstmt 对象 pstmt = con.prepareStatement(sql); // 读取 rs = pstmt.executeQuery(); if (rs.next()) { // 获取长文本数据, 方式1: //Reader r = rs.getCharacterStream("content"); // 获取长文本数据, 方式2: System.out.print(rs.getString("content")); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, null); } } } |
blob |
public class App_blob { // 全局参数 private Connection con; private Statement stmt; private PreparedStatement pstmt; private ResultSet rs; @Test // 1. 二进制数据类型 ( 写longblob) public void testSaveText() { String sql = "insert into test(img) values(?)"; try { // 连接 con = JdbcUtil.getConnection(); // pstmt 对象 pstmt = con.prepareStatement(sql); // 获取图片流 InputStream in = App_text.class.getResourceAsStream("7.jpg"); pstmt.setBinaryStream(1, in); // 执行保存图片 pstmt.execute(); // 关闭 in.close(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, null); } } @Test // 2. 读取大文本数据类型 ( 读longblob) public void testGetAsText() { String sql = "select img from test where id=2;"; try { // 连接 con = JdbcUtil.getConnection(); // pstmt 对象 pstmt = con.prepareStatement(sql); // 读取 rs = pstmt.executeQuery(); if (rs.next()) { // 获取图片流 InputStream in = rs.getBinaryStream("img"); // 图片输出流 FileOutputStream out = new FileOutputStream(new File("c://1.jpg")); int len = -1; byte b[] = new byte[1024]; while ((len = in.read(b)) != -1) { out.write(b, 0, len); } // 关闭 out.close(); in.close(); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.closeAll(con, pstmt, null); } } } |