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

原子性(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);

}

}

}

Java jdbc入门的更多相关文章

  1. JAVA企业级开发-jdbc入门(09)

    一. jdbc介绍 JDBC全称为:Java DataBase Connectivity(java数据库连接). SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JD ...

  2. 自学 Java 怎么入门

    自学 Java 怎么入门? 595赞同反对,不会显示你的姓名     给你推荐一个写得非常用心的Java基础教程:java-basic | 天码营 这个教程将Java的入门基础知识贯穿在一个实例中,逐 ...

  3. 《JAVA 从入门到精通》 - 正式走向JAVA项目开发的路

    以前很多时候会开玩笑,说什么,三天学会PHP,七天精通Nodejs,xx天学会xx ... 一般来说,这样子说的多半都带有一点讽刺的意味,我也基本上从不相信什么快速入门.我以前在学校的时候自觉过很多门 ...

  4. Jdbc入门

    JDBC入门 l  导jar包:驱动! l  加载驱动类:Class.forName(“类名”); l  给出url.username.password,其中url背下来! l  使用DriverMa ...

  5. day17(JDBC入门&jdbcUtils工具介绍)

    day17 JDBC整体思维导图 JDBC入门 导jar包:驱动! 加载驱动类:Class.forName("类名"); 给出url.username.password,其中url ...

  6. java秀发入门到优雅秃头路线导航【教学视频+博客+书籍整理】

    目录 一.Java基础 二.关于JavaWeb基础 三.关于数据库 四.关于ssm框架 五.关于数据结构与算法 六.关于开发工具idea 七.关于项目管理工具Mawen.Git.SVN.Gradle. ...

  7. 【JDBC】JDBC入门

    JDBC的入门 搭建开发环境 编写程序,在程序中加载数据库驱动 建立连接 创建用于向数据库发送SQL的Statement对象 从代表结果集的ResultSet中取出数据 断开与数据库的连接,并释放相关 ...

  8. 1 初识数据库操作 2 JDBC 入门

    1 JDBC:Java Database Connectivity(Java 数据库连接) 1.1 JDBC 入门程序 注册驱动:Class.forName("com.mysql.cj.jd ...

  9. java jdbc 连接mysql数据库 实现增删改查

    好久没有写博文了,写个简单的东西热热身,分享给大家. jdbc相信大家都不陌生,只要是个搞java的,最初接触j2ee的时候都是要学习这么个东西的,谁叫程序得和数据库打交道呢!而jdbc就是和数据库打 ...

随机推荐

  1. 题目1016:火星A+B(字符串拆分)

    问题来源 http://ac.jobdu.com/problem.php?pid=1016 问题描述 每次输入两个数,不同数位之间用逗号隔开,其中,第n位的进制就是第n个素数,即个位数是2进制的,十位 ...

  2. lua小试牛刀

    function function max(num1, num2) if(num1 > num2) then result = num1; else result = num2; end ret ...

  3. http、tcp及从请求到渲染的过程

    http.tcp及从请求到渲染的过程 https://blog.csdn.net/pambassador/article/details/88539478 http请求的结构内容 https://ww ...

  4. Java Web基础——Controller+Service +Dao三层的功能划分

    转自:https://www.cnblogs.com/cielosun/articles/5752272.html 1. Controller/Service/DAO简介: Controller是管理 ...

  5. UGUI Slider的onValueChanged事件

    在本文,你将学到如何将UGUI Slider的onValueChanged事件进行统一管理. using System; using UnityEngine; using UnityEngine.UI ...

  6. init_config_file.lua

    --[[ 读取限流配置 --]] --获取共享内存 local limit_req_store = ngx.shared.limit_req_store --初始化拒绝 URI 列表 reject_u ...

  7. opencv-python 读入带有中文的图片路径

    windows 下读入带有中文的图片路径使用cv2.imread() 不能读入.使用如下代码可以. def cv_imread(filePath): cv_img = cv2.imdecode(np. ...

  8. 10个重要的算法C语言实现源代码

    包括拉格朗日,牛顿插值,高斯,龙贝格,牛顿迭代,牛顿-科特斯,雅克比,秦九昭,幂法,高斯塞德尔 .都是经典的数学算法,希望能开托您的思路.转自kunli.info 1.拉格朗日插值多项式 ,用于离散数 ...

  9. c++ 网络编程(九)LINUX/windows-IOCP模型 多线程超详细教程及多线程实现服务端

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9661012.html 先讲Linux下(windows下在后面可以直接跳到后面看): 一.线程 ...

  10. 【debian】解决debian中文安装后出现乱码的问题

    由于安装debian选择语言时选择了简体中文安装,但内核没有中文字库,导致某些字符显示为乱码(菱形,方块). 解决办法: 普通用户如果没有设置sudo权限,首先切换到root权限.然后: apt-ge ...