Java jdbc入门

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语句(DDLDML

|- ResultSet executeQuery(String sql)  :执行的静态的查询sql语句(DQL

|-PreparedStatement接口:用于执行预编译sql语句

|- int executeUpdate() 执行预编译的更新sql语句(DDLDML

|-ResultSet executeQuery()   执行预编译的查询sql语句(DQL

|-CallableStatement接口:用于执行存储过程的sql语句(call xxx

|-ResultSet executeQuery()   调用存储过程的方法

|- ResultSet接口:用于封装查询出来的数据

|- boolean next()  将光标移动到下一行

|-getXX() : 获取列的值

使用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);

}

}

}

使用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特性

原子性(Atomicity
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 

一致性(Consistency
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

隔离性(Isolation
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性(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);

}

}

}

原文地址:https://www.cnblogs.com/burningmyself/p/7114658.html