使用java代码(程序)发送sql语句的技术,就是jdbc技术!
JDBC与数据库之间的通信是通过Socket完成的,因此我们可以把数据库当成一个SocketServer的提供方,因此当SocketServer返回数据的时候(类似于SQL结果集的返回)其流程是:服务端程序数据(数据库) -> 内核Socket Buffer -> 网络 -> 客户端Socket Buffer -> 客户端程序(JDBC所在的JVM内存)
数据库收到sql语句后执行步骤:
- 检查语法是否正确
- 检查是否有足够的权限
- 把sql加入到sql缓冲区
- 数据库取出sql缓冲区的执行任务执行
使用jdbc发送sql前提:
登录数据库服务器(连接数据库服务器)
数据库的IP地址,端口
数据库用户名,密码
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对象
|- void setAutoCommit(boolean autoCommit) ; -设置事务是否自动提交。设置为false,表示手动提交事务。
|- void commit(); -手动提交事务
|- void rollback() ; -回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)
|- Savepoint setSavepoint(String name) -在当前事务创建一个给定名称的保存点,并返回表示它的新Savepoint 对象
|- Statement接口: 用于执行静态的sql语句
|- boolean execute(String sql) : 增删改查(true表示执行的是查询语句,false表示执行的是insert,delete,update等)
|- ResultSet getResultSet(): 获取查询结果
|- int executeUpdate(String sql) : 增删改(DDL,DML)返回影响行数
|- ResultSet executeQuery(String sql) : 查(DQL)
|- void addBatch(String sql): -添加批处理
|- void clearBatch(): -清空批处理
|- int[] executeBatch(): -执行批处理
|-- PreparedStatement接口: 用于执行预编译sql语句
|- int executeUpdate() : 执行预编译的更新sql语句(DDL,DML)
|-ResultSet executeQuery() : 执行预编译的查询sql语句(DQL)
|- void setXXX(int parameterIndex, value) : 将指定参数设置为给定值
|--- CallableStatement接口: 用于执行存储过程的sql语句(call xxx)
-ResultSet executeQuery() : 调用存储过程的方法
|- ResultSet接口: 用于封装查询出来的数据
|- boolean next() : 将光标移动到下一行 光标指向当前行数据,没有下一行时返回false
|- getXX() : 从当前行获取列的值 可以通过 索引编号(从1开始) 或列名称(不区分大小写) 获取值
JDBC连接到数据库的3种方式
public class Demo {
//连接数据库的URL
private String url = "jdbc:mysql://localhost:3306/day17"; //jdbc协议:数据库子协议:主机:端口/连接的数据库
private String user = "root"; //用户名
private String password = "123456"; //密码
1.用驱动程序连接
public void test1() throws Exception{
//1.创建驱动程序类对象
//Driver driver = new org.gjt.mm.mysql.Driver(); //旧版本
Driver driver = new com.mysql.jdbc.Driver(); //新版本
//设置用户名和密码
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
//2.连接数据库,返回连接对象conn
Connection conn = driver.connect(url, props);
}
2.用驱动管理器类连接数据库
public void test2() throws Exception{
Driver mysql_driver = new com.mysql.jdbc.Driver();
Driver oracle_driver = new com.oracle.jdbc.Driver();
//1.注册驱动程序(可以注册多个驱动程序)
DriverManager.registerDriver(mysql_driver);
DriverManager.registerDriver(oracle_driver);
//2.连接到具体的数据库,获取连接对象conn
Connection conn = DriverManager.getConnection(url, user, password);
}
--3.加载驱动程序类来注册驱动程序 (推荐使用)
public void test3() throws Exception{
//1.通过得到字节码对象的方式加载静态代码块,加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.连接到具体的数据库,获取连接对象conn
Connection conn = DriverManager.getConnection(url, user, password);
}
}
使用Statement执行sql语句
1.执行DDL语句:
数据定义语言(create / drop / alter)
//执行DDL语句(创建表)
public void test1(){
Statement stmt = null;
Connection conn = null;
try {
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象conn
conn = DriverManager.getConnection(url, user, password);
//3.创建Statement对象stmt
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.执行DML语句:
数据操作语句(insert / delete /update / truncate)
JdbcUtil:创建一个工具类,将数据库的注册驱动程序,获取连接对象,释放资源等公共步骤 都包装JdbcUtil工具类中,使用时直接调用
增加
public void testInsert(){
Connection conn = null;
Statement stmt = null;
try {
//1.通过工具类获取连接对象
conn = JdbcUtil.getConnection();
//2.创建Statement对象
stmt = conn.createStatement();
//3.sql语句
String sql = "INSERT INTO student(NAME,gender) VALUES('李四','女')";
//4.执行sql
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally{
//关闭资源
JdbcUtil.close(conn, stmt);
}
}
修改
public void testUpdate(){
Connection conn = null;
Statement stmt = null;
//模拟用户输入
String name = "陈六";
int id = 3;
try {
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
String sql = "UPDATE student SET NAME='"+name+"' WHERE id="+id+"";
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
} catch (Exception e) {···} finally{···}
}
删除
public void testDelete(){
Connection conn = null;
Statement stmt = null;
//模拟用户输入
int id = 3;
try {
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
String sql = "DELETE FROM student WHERE id="+id+"";
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
} catch (Exception e) {···} finally{···}
}
3.执行DQL语句:
数据查询语言(select / show)
public void test(){
Connection conn = null;
Statement stmt = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
String sql = "SELECT * FROM student";
//执行sql,返回结果ResultSet对象
ResultSet rs = stmt.executeQuery(sql);
//*移动光标,遍历结果
while(rs.next()){
//1.根据索引 取出列值
int id = rs.getInt(1);
String name = rs.getString(2);
String gender = rs.getString(3);
//2.根据列名称 取出列值
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
System.out.println(id+","+name+","+gender);
}}catch(Exception e){···}finally{···}
}
使用预编译PreparedStatement执行sql语句
? 表示一个参数的占位符
增加
public void testInsert() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1.获取连接
conn = JdbcUtil.getConnection();
//*2.准备预编译的sql
String sql = "INSERT INTO student(NAME,gender) VALUES(?,?)"; //?表示一个参数的占位符
//*3.执行预编译sql语句(只检查语法,不执行) --- sql语句放入缓冲区,没有参数
pstmt = conn.prepareStatement(sql);
//*4.设置参数值
/**
* 参数一: 参数位置,从1开始
* 参数二: 具体数据
*/
pstmt.setString(1, "李四");
pstmt.setString(2, "男");
//*5.发送参数,执行sql --- 参数传入缓冲区并执行
int count = pstmt.executeUpdate();
System.out.println("影响了"+count+"行");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
JdbcUtil.close(conn, pstmt);
}
}
修改
······
//2.准备预编译的sql
String sql = "UPDATE student SET NAME=? WHERE id=?"; //?表示一个参数的占位符
//3.执行预编译sql语句(检查语法)
pstmt = conn.prepareStatement(sql);
//4.设置参数值
pstmt.setString(1, "王五");
pstmt.setInt(2, 9);
//5.发送参数,执行sql
int count = pstmt.executeUpdate();
System.out.println("影响了"+count+"行");
······
删除
······
//2.准备预编译的sql
String sql = "DELETE FROM student WHERE id=?"; //?表示一个参数的占位符
//3.执行预编译sql语句(检查语法)
pstmt = conn.prepareStatement(sql);
//4.设置参数值
pstmt.setInt(1, 9);
//5.发送参数,执行sql
int count = pstmt.executeUpdate();
System.out.println("影响了"+count+"行");
······
查询
······
//1.获取连接
conn = JdbcUtil.getConnection();
//2.准备预编译的sql
String sql = "SELECT * FROM student";
//3.预编译
pstmt = conn.prepareStatement(sql);
//4.执行sql
rs = pstmt.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);}
//关闭 rs,pstmt,conn ······
PreparedStatement 对比 Statment
- 语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
- 效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
- 安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。
推荐使用PreparedStatement
使用CallableStatement执行存储过程
sql存储过程:
DELIMITER $
CREATE PROCEDURE pro_findById(IN sid INT,OUT sname VARCHAR(20) )
BEGIN
SELECT Name INTO sname FROM student WHERE id=sid;
END $
执行带有输入输出参数的存储过程:
注意: 所有调用存储过程的sql语句都是使用executeQuery方法执行!
public void test(){
Connection conn = null;
CallableStatement cstmt = null;
ResultSet rs = null;
try {
//获取连接
conn = JdbcUtil.getConnection();
//准备sql
String sql = "CALL pro_findById(?,?)"; //第一个?是输入参数,第二个?是输出参数
//预编译
cstmt = conn.prepareCall(sql);
//*设置输入参数
cstmt.setInt(1, 6);
//*设置输出参数(注册输出参数)
/**
* 参数一: 参数位置
* 参数二: 存储过程中的输出参数的jdbc类型 VARCHAR(20)
*/
cstmt.registerOutParameter(2, java.sql.Types.VARCHAR);
//*发送参数,执行 //注意: 所有调用存储过程的sql语句都是使用executeQuery方法执行!
cstmt.executeQuery(); //结果不是返回到ResultSet结果集中,而是返回到输出参数中
//*得到输出参数的值
/**
* 索引值: 预编译sql中的输出参数的位置
*/
String result = cstmt.getString(2); //CallableStatement的getXX方法专门用于获取存储过程中的输出参数
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
JdbcUtil.close(conn, cstmt ,rs);
}
}
-批处理
批量保存信息,批量执行sql语句
//获取连接 -> 准备sql -> 创建stmt ->
//添加批处理
stmt.addBatch(sql1); //Statement添加需要传入sql语句,
stmt.addBatch(sql2);
stmt.addBatch(sql3);
pstmt.setXXX(1,value1);//PreparedStatement要先设置参数
pstmt.setXXX(2,value2);
pstmt.setXXX(3,value3);
pstmt.addBatch(); //PreparedStatement添加不需要传入SQL
//批量执行
stmt.executeBatch();
//清空批处理
stmt.clearBatch();
//关闭连接
-获取插入数据的自增长值
//1.创建PreparedStatement对象时,在参数中指定返回自增长标记
pstmt = conn.prepareStatement(sql_dept, Statement.RETURN_GENERATED_KEYS);
······
//2.执行sql语句更新后,获取自增长列
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
autoId = rs.getInt(1);
}
事物
基本概念:
事务是指一组最小逻辑操作单元,里面有多个操作组成。 组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。
事务ACID特性:
原子性(Atomicity) 是一个最小逻辑操作单元
事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency) 事务过程中,数据处于一致状态
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
隔离性(Isolation) 事务与事务之间是隔离的
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability) 事务一旦提交成功,对数据的更改会反映到数据库中
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
API:
|- void setAutoCommit(boolean autoCommit) ; -设置事务是否自动提交。默认添加并为为true。设置为false,表示手动提交事务。
|- void commit(); -手动提交事务
|- void rollback() ; -回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)
|- Savepoint setSavepoint(String name) -在当前事务创建一个给定名称的保存点,并返回表示它的新Savepoint 对象
// 例:转账,使用事务,回滚到指定的代码段
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 {
conn = JdbcUtil.getConnection(); // 默认开启的隐式事务自动提交
conn.setAutoCommit(false); // 主动设置为事务手动提交
/*** 第一次转账 ***/
pstmt = conn.prepareStatement(sql_zs1);
pstmt.executeUpdate();
pstmt = conn.prepareStatement(sql_ls1);
pstmt.executeUpdate();
//*保存点,回滚到sp这个位置
sp = conn.setSavepoint();
/*** 第二次转账 ***/
pstmt = conn.prepareStatement(sql_zs2);
pstmt.executeUpdate();
pstmt = conn.prepareStatement(sql_ls2);
pstmt.executeUpdate();
} catch (Exception e) {//出现异常,回滚事物
try {
conn.rollback(sp); // 回滚 Savepoint对象之后进行的更改
conn.rollback(); // 回滚 当前事务中进行的所有更改
} catch (SQLException e1) {
}
e.printStackTrace();
} finally {
try {
// 提交
conn.commit();
} catch (SQLException e) {
}
JdbcUtil.closeAll(conn, pstmt, null);
}
}
Jdbc中大文本类型的处理
Oracle中大文本数据类型,
Clob 长文本类型 (MySQL中不支持,使用的是text)
Blob 二进制类型
MySQL数据库,
Text 长文本类型
Blob 二进制类型
-- 例:大数据类型
CREATE TABLE test(
id INT PRIMARY KEY AUTO_INCREMENT,
content LONGTEXT,
img LONGBLOB
);