访问数据库的技术叫JDBC,对数据库的数据进行添加,删除,修改和查询
JDBC的API,存放在java.sql包中
java.sql.Connection:负责连接数据库
java.sql.Statement:负责执行数据库sql语句
java.sql.ResultSet:负责存放查询结果
JDBC
JDBC是一套面向对象的应用程序接口,指定了统一的访问各种关系型数据库的标准接口。JDBC是一种底层的API,因此访问数据库时需要嵌入SQL语句。
JDBC主要完成以下几个任务
1.与数据库建立连接
2.向数据库发送SQL语句
3.处理从数据库返回的结果
JDBC的总体结构由4个组件构成:应用程序,驱动程序管理器,驱动程序和数据源
JDBC驱动程序类型
JDBC并不能直接访问数据库,必须依赖于数据库厂商提供的JDBC驱动程序。
JDBC驱动基本分为以下几种
1.JDBC-ODBC桥:依靠ODBC驱动器和数据库通信。这种连接方式必须将ODBC二进制代码加载到使用该驱动程序的每台客户机上。
2.本地API一部分用java编写的驱动程序:这类驱动程序把客户机的API上的JDBC调用转换为Oracle,DB2,Sybase或其他DBMS的调用。这种驱动程序也需要将某些二进制代码加载到每台客户机上,
3.JDBC网络驱动:这种驱动程序将JDBC转换为与DBMS无关的网络协议,又被某个服务器转换为一种DBMS协议,是一种利用java编写的JDBC驱动程序,也是最为灵活的JDBC驱动程序。这种方案的提供者提供了适合于企业内部互联网用的产品。为使这种产品支持Internet访问,需要处理Web提出的安全性,通过防火墙的访问等额外的要求。
4.本地协议驱动:这是一种纯java的驱动程序。这种驱动程序将JDBC调用直接转换为DBMS所使用的网络协议,允许从客户机上直接调用DBMS服务器
JDBC网络驱动和本地协议驱动是JDBC访问数据库的首选,这两类驱动程序提供了java的所有优点。
各种数据库产品不同,厂商也不同,连接的方式也不同。JDBC机制提供了“驱动程序"的概念。对于不同的数据库,程序只需要使用不同的驱动。这种连接数据库的一种方式:数据库厂商驱动
在微软公司的Windows中,预先设计了一个ODBC(开放数据库互连)功能,由于ODBC是微软公司的产品,所以它几乎可以连接到所有在Windows平台下运行的数据库,由它连接到特定的数据库,不需要具体的驱动。而JDBC就只需要连接到ODBC就可以了。通过ODBC就可以连接到ODBC支持的任意一种数据库,这种连接方式称为JDBC-ODBC桥。这种方法让java连接到数据库的驱动程序称为JDBC-ODBC桥接驱动器。
JDBC-ODBC桥
JDBC-ODBC桥是一个JDBC驱动程序,完成从JDBC到ODBC操作之间的转换工作。
JDBC桥作为连接数据库的过渡技术,现在已经不被广泛应用了。但不代表其已经被淘汰。java可以利用JDBC-ODBC桥访问几乎所有的数据库。
使用JDBC-ODBC桥连接数据库的步骤如下
1.加载JDBC-ODBC桥的驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
通过Class类的静态方法forName()可加载sun,jdbc,odbc包中的JdbcOdbcDriver类来建立JDBC-ODBC桥
2.使用Connection接口,并通过DriverManager类的静态方法getConnection()创建连接对象
Connection conn= DriverManager.getConnection(”jdbc:odbc:数据源名字“,"user name","password");
3.向数据库发送SQL语句
使用Statement接口声明一个SQL语句对象,并通过刚才创建的连接数据库对象conn的createStatement()方法创建这个SQL对象
Statement sql=conn.createStatement();
JDBC中常用的类和接口
(1)Connection接口
Connection接口代表与特定的数据库的连接
常用方法
方法 | 说明 |
---|---|
createStatement() | 创建Staement对象 |
createStatement(int resultSetType,int resultSetConcurrency) | 创建一个Statement对象,该对象将生成具有给定类型,并发性和可保存性的ResultSet对象 |
preparedStatement(String sql) | 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。 |
isReadOnly() | 检索此 Connection对象是否处于只读模式。 |
setReadOnly(boolean readOnly) | 将此连接设置为只读模式,默认是非只读模式。 |
commit() | 使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁。 |
rollback() | 撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁。 |
close() | 立即释放此 Connection对象的数据库和JDBC资源,而不是等待它们被自动释放 |
(2)Statement接口
statement是java中的一个连接数据库的一个重要接口,在建立与数据库的连接之后,向数据库发送执行的sql语句(执行不带参数的简单sql)
JDBC中有三种Statement 接口
1.Statement :执行不带参数的简单sql
2.PreparedStatement (PreparedStatement 继承Statment) :执行动态的sql语句
3.CallableStatement (CallableStatement继承PreparedStatement ) :执行对数据库的存储过程的调用
Statement的常用方法
方法 | 说明 |
---|---|
excute(String sql) | 执行静态的select语句,语句可能返回多个结果集 |
executeQuery(String sql) | 执行给定的select语句,语句返回单个Resultset对象 |
excutebatch() | 将一批命令交给数据库执行,如果全部命令执行成功,则返回更新计数组成的数组。数组元素的顺序与添加sql语句的顺序对应 |
addBatch(String sql) | 将给定的sql命令添加到此Statement对象的当前命令列表中。如果程序不支持批量处理,将抛出异常 |
executeUpdate() | 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数,指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。 |
close() | 释放Statement实例占用的数据库和JDBC资源 |
少量语句Statement可能会发生SQL注入危险,所以一般不使用
大量语句使用Statement的addBatch
(3)PreparedStatement接口
PreparedStatement接口用来动态的执行SQL语句。通过PreparedStatement实例执行的动态SQL语句,将被预编译并保存到PreparedStatement实例中,从而可以反复地执行该SQL语句
PreparedStatement接口的常用方法
方法 | 说明 |
---|---|
.executeQuery() | 在此PreparedStatement对象中执行SQL查询,并返回该查询生成的ResultSet对象 |
.excuteUpate() | 执行前面包含参数的动态INSERT,UPDATE或DELETE语句,返回一个整型 |
setXXX(int dex,object o) | XXX为设置参数的类型,object的类型对应XXX的类型(int,FLoat,Long,Double,Boolean,Date,String) 将指定位置的参数设置为XXX值 |
clearParameters() | 清除当前所有参数的值 |
预处理语句
通过Connection对象的PreparedStatement(String sql)方法对SQL语句进行预处理,生成数据库底层的内部命令,并将该命令封装在PreparedStatement对象中。通过调用相应方法,执行底层数据库命令。
预处理可以使用通配符“? ”来代替任何字段值
PreparedStatement sql=con.preparedStatement("select *from tb_stu where id="?");
然后通过setXXX来设置通配符所表示的值
sql.setint(1,2);
//1表示从左到右的第一个通配符,2表示设置的通配符的值
注:setXXX使用参数匹配的方法,还可以setObject()方法为各种类型的参数赋值 如:sql.setObject(2,1);
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
try {
PreparedStatement sql=conn.prepareStatement("select * from tb_student where id= ?"); //预处理语句
sql.setInt(1,19);
ResultSet res=sql.executeQuery();
while(res.next()){
String id=res.getString("id");
String name=res.getString("name");
String sex=res.getString("sex");
System.out.println("学号:"+id+"姓名:"+name+"性别:"+sex);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(4)CallableStatement 接口
除了PreparedStatement外,还提供了CallableStatement 来调用存储过程。CallableStatement 是PreparedStatement的子接口
可以通过Connection的prepareCall()方法创建CallableStatement 对象,使用CallableStatement 对象可以同时处理IN参数和OUT参数
常用方法
方法 | 说明 |
---|---|
setXXX() | 设置IN参数 |
registerOutParameter(int parameterIndex, SQLType sqlType) | 将序号parameterIndex中的OUT参数 parameterIndex到JDBC类型 sqlType |
getXXX() | 获取参数值 |
如何调用这个存储过程
CallableStatement对象通过setXXX()方法传入IN参数,如果已定义的存储过程返回OUT参数,则在执行CallableStatement对象以前必须先注册每个OUT参数的JDBC类型,注册JDBC类型通过registerOutParameter()方法实现。语句执行完后,CallableStatement的getXXX()方法获取参数值。XXX表示各参数所注册的JDBC类型所对应的java类型
如一个例子,根据学生学号,查询其姓名
CRATE PROCEDURE prc_getStuname(@stuno VARCHAR(16),@stuname VARCHAR(16) OUTPUT)
AS
BEGIN
SELECT @stuname=STUNAME FROM T_STUDENT WHERE STUNO=@stuno
END
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
conn = DriverManager.getConnection("jdbc:odbc:Dsschool"); //与数据源建立连接
CallableStatement cs=conn.prepareCall("{call prc_getStuname(?,?)}");
cs.setString(1,"0001"); //设置IN参数
cs.registerOutParameter(2, Types.CHAR); //注册OUT参数
cs.executeQuery(); //执行存储过程
String result=cs.getString(2); //获取参数值
cs.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Statement 接口提供了执行语句和获取结果的基本方法。PreparedStatement 接口添加了处理 IN 参数的方法;而 CallableStatement 添加了处理 OUT 参数的方法。
(5)DriverManager类
DriverManager类用来管理数据库中的所有驱动程序。它是JDBC的管理层,作用于用户和驱动程序之间,跟踪可用的驱动程序,并在数据库的驱动程序之间建立连接,如果通过getConnection()方法可以建立连接,则经连接返回,否则抛出SQLException
异常。zhid
常用方法
方法 | 说明 |
---|---|
getConnection(String url,String user,String password) | 指定3个入口参数(连接数据库的URL,用户名,密码)来获取与数据库的连接 |
setLoginTimeout() | 获取驱动程序试图登录到某一数据库时可以等待的最长时间,以秒为单位 |
println(String message) | 将一条消息打印到当前JDBC日志流中 |
(6)ResultSet接口
ResuleSet接口类似一个临时表,用来暂时存放数据库查询操作所获得的结果集。并且ResultSet还提供当前数据行的指针,指针刚开始指向第一行,通过next()方法移向下一行
ResultSet接口常用方法
方法 | 说明 |
---|---|
getXXX() | 以xxx形式获取此ResultSet对象的当前行的指定列值。如果列值是NULL,则返回0 |
first() | 将指针移到当前记录的第一行 |
last() | 将指针移到当前记录的最后一行 |
next() | 将指针向下移一行 |
absolute(int index) | 将指针移到ResultSet给定编号的行 |
updateXXX() | 用xxx值更新指定列 |
getrow() | 查看当前行的索引号 |
insertRow() | 将插入行的内容插入到数据库 |
updateRow() | 将当前行的内容同步到数据库 |
deleteRow() | 删除当前行,但并不同步到数据库中,而是在执行close()方法同步到数据库 |
用updateXXX()更新指定列。但该方法没有对数据同步到数据库中,需要执行updateRow()或insertRow()方法更新数据库
数据库操作
(1)连接数据库
访问数据库,首先要加载数据库的驱动程序(只需要在第一次访问数据库时加载一次),然后每次访问数据时创建一个Connection对象,接着执行操作数据库的SQL语句,最后在完成数据库操作后销毁前面创建的Connection对象,释放与数据库的连接
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //8.0版本 使用com.mysql.cj.jdbc.Driver 老版本使用com.mysql.jdbc.Driver
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
如果连接出现这种情况
conn = DriverManager.getConnection(“jdbc:mysql://127.0.0.1:3306/test”,“root”,“123456”); 就改成 con= DriverManager.getConnection(“jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC”,“root”,“123456”);
在后面加**?serverTimezone=UTC**
(2)向数据库发送SQL语句
要执行SQL语句首先要获得Statement类对象。通过Connection对象的createStatement()方法获取Statement对象
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //8.0版本 使用com.mysql.cj.jdbc.Driver 老版本使用com.mysql.jdbc.Driver
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
try {
Statement sql=conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(3)处理查询结果集
通过Statement对象的相应方法实现对数据库的查询和修改,并将查询的结果集存放在ResultSet类的对象中
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //8.0版本 使用com.mysql.cj.jdbc.Driver 老版本使用com.mysql.jdbc.Driver
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
try {
Statement sql=conn.createStatement();
ResultSet res=sql.executeQuery("select * from tb_student");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
返回一个ResultSet对象,ResultSet对象一次只可以看到结果集中的一行数据,使用该类的next()方法可将光标从当前位置移向下一行
ResultSet类的next()方法的返回值是boolean类型,当游标移动到最后一行之后会返回false。
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //8.0版本 使用com.mysql.cj.jdbc.Driver 老版本使用com.mysql.jdbc.Driver
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
try {
Statement sql=conn.createStatement();
ResultSet res=sql.executeQuery("select * from tb_student");
while(res.next()){
String id=res.getString("id");
String name=res.getString("name");
String sex=res.getString("sex");
System.out.println("学号:"+id+"姓名:"+name+"性别:"+sex);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
预处理语句PreparedStatement
存储过程CallableStatement
前面有
(4)添加,修改,删除记录
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
PreparedStatement sql;
ResultSet res;
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //8.0版本 使用com.mysql.cj.jdbc.Driver 老版本使用com.mysql.jdbc.Driver
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
}
try {
sql=conn.prepareStatement("select * from tb_student");
System.out.println("------增添删改操作之前的数据------");
res=sql.executeQuery();
while(res.next()){
String id=res.getString("id");
String name=res.getString("name");
String sex=res.getString("sex");
System.out.println("学号:"+id+"姓名:"+name+"性别:"+sex);
}
sql=conn.prepareStatement("insert into tb_student values (?,?,?)"); //插入
sql.setString(1,"0005");
sql.setString(2,"张三");
sql.setString(3,"男");
sql.executeUpdate();
sql=conn.prepareStatement("uddate tb_studnet set name =? where id="+"0001"); //更新
sql.setString(1,"小李");
sql.executeUpdate();
sql=conn.prepareStatement("delete tb_studnet where id="+"0002"); //删除
sql.executeUpdate();
System.out.println("------增添删改操作之后的数据------");
sql=conn.prepareStatement("select * from tb_student");
res=sql.executeQuery();
while(res.next()){
String id=res.getString("id");
String name=res.getString("name");
String sex=res.getString("sex");
System.out.println("学号:"+id+"姓名:"+name+"性别:"+sex);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(4)批处理Batch
当需要处理大量的SQL语句时,就需要Batch。尽量使用Statement,因为prepareStatement预编译空间有限,当数据量特别大时会发生异常。
另外批处理时需要将事务自动提交改为false
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
Statement st;
ResultSet res;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动加载成功");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
conn.setAutoCommit(false); //设为手动提交
st=conn.createStatement();
for(int i=0;i<20000;i++){
st.addBatch("insert into tb_student (stnuo,stuname) values("+i+",'gao')");
}
st.executeBatch();
conn.commit(); //提交
} catch (SQLException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
(5)时间段查询
java.sql.Date:表示年月日
java.sql.Time:表示时分秒
java.sql.Timestamp:表示年月日时分秒
构造方法需要传入long类型参数
import java.sql.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Test {
public static long getTime(String datestr){ //datestr格式:yyyy-MM-dd hh:mm:ss
DateFormat format=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
try {
return format.parse(datestr).getTime();
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
public static void main(String[] args) {
Connection conn= null;
PreparedStatement sql;
PreparedStatement sql2;
ResultSet res;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动加载成功");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
sql=conn.prepareStatement("select * from tb_user where regtime>? and regtime<?");
java.sql.Date start=new java.sql.Date (getTime("2019-10-01 21:23"));
java.sql.Date end=new java.sql.Date (getTime("2019-10-07 21:23"));
sql.setObject(1,start);
sql.setObject(2,end);
res=sql.executeQuery();
while (res.next()){
System.out.println(res.getInt("id")+" "+res.getString("username")+" "+res.getString("regtime"));
}
}catch (ClassNotFoundException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
事务
(1).事务
事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位
事务开始于
·连接数据库操作,并执行一条DML语句(INSERT,UPDATE或DELETE)
·前一个事务结束后,又输入了另一条DML语句
事务结束于
·执行COMMIT或ROLLBACK语句
·执行一条DDL语句,这种情况下会自动执行COMMIT语句
·执行一条DCL语句,这种情况下会自动执行COMMIT语句
·断开数据库的连接
·执行一条DML语句,该语句失败了,这种情况下,会执行ROLLBACK语句
事务的ACID特性
1.原子性
事务时数据库的逻辑工作单位,事务中包括的操作要么都做,要么都不做
2.一致性
表示一个事务有一个事务操作失败时,所有更改的数据必须回到修改以前的状态
3.隔离性
一个事务的执行不能被其他事务干扰。即一个事务的内部操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰
4.持久性
一个事务一旦提交,它对数据库中数据的改变就是永久性的
事务隔离级别从低到高
·读取未提交 :也就是事务A在执行时,还未提交时,事务B可以看到
·读取已提交:事务A在执行时,在已提交后事务B才可以看到
·可重复读
·序列化:锁表
一般情况下都是读取已提交。
(2)事务操作
package Learn;
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
PreparedStatement sql;
PreparedStatement sql2;
ResultSet res;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动加载成功");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
conn.setAutoCommit(false); //JDBC默认是true,自动提交 设为手动提交
sql=conn.prepareStatement("insert into tb_student(stuno,stuname) values(?,?)"); //事务开始
sql.setString(1,"0001");
sql.setString(2,"张三");
sql.execute();
sql2=conn.prepareStatement("insert into tb_student(stuno,stuname) values(?,?)");
sql2.setString(1,"0001");
sql2.setString(2,"张三");
sql2.execute();
conn.commit(); //提交 事务结束
}catch (ClassNotFoundException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上述事务的操作会成功
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn= null;
PreparedStatement sql;
PreparedStatement sql2;
ResultSet res;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动加载成功");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC","root","123456");
System.out.println("数据库连接成功");
conn.setAutoCommit(false); //JDBC默认是true,自动提交 设为手动提交
sql=conn.prepareStatement("insert into tb_student(stuno,stuname) values(?,?)"); //事务开始
sql.setString(1,"0001");
sql.setString(2,"张三");
sql.execute();
sql2=conn.prepareStatement("insert into tb_student(stuno,stuname) values(?,?,?)");
sql2.setString(1,"0001");
sql2.setString(2,"张三");
sql2.execute();
conn.commit(); //提交 事务结束
}catch (ClassNotFoundException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上述代码事务的第二个操作会执行失败,会出现异常,执行回滚操作ROLLBACK
CLOB(Character Large Object)
用于存储大量的文本数据,比如存本小说
大字段的操作常常是以流的方式来处理。
MySQl中相关类型
TINYTEXT最大长度为255(21–1)字符的TEXT列。
TEXT[(M)]最大长度为65,535(22–1)字符的TEXT列。
MEDIUMTEXT最大长度为16,777,215(23–1)字符的TEXT列。
LONGTEXT最大长度为4,294,967,295或4GB(24–1)字符的TEXT列。
向MySQL中插入CLOB数据
使用PreparedStatement的setClob(int index,Reader reader)方法 第一个参数是占位符的坐标,第二个参数是输入流
将info.txt文件的内容读入到SQL
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class CLOB {
public static void main(String[] args) {
Connection con=null;
PreparedStatement ps=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
ps=con.prepareStatement("insert into user (name,info) values (?,?)");
ps.setString(1,"张三");
ps.setClob(2,new FileReader("d:/info.txt"));
ps.executeUpdate();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
得到CLOB
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.sql.*;
public class CLOB {
public static void main(String[] args) {
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
Reader reader=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
ps=con.prepareStatement("insert into user (name,info) values (?,?)");
ps.setString(1,"张三");
ps.setClob(2,new FileReader("d:/info.txt"));
ps.executeUpdate();
ps=con.prepareStatement("select * from user where id>?");
ps.setObject(1,1);
rs=ps.executeQuery();
while(rs.next()){
Clob clob=rs.getClob("info"); //读取CLOB
reader=clob.getCharacterStream();
int temp=0;
while((temp=reader.read())!=-1){
System.out.println((char) temp);
}
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(rs!=null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
BOLB
用于存储大量的二进制数据
也是用流来处理的
Mysql中相关类型:
TINYBLOB最大长度为255(25–1)字节的BLOB列。
BLOB[(M)]最大长度为65,535(26–1)字节的BLOB列。
MEDIUMBLOB最大长度为16,777,215(27–1)字节的BLOB列。
LONGBLOB最大长度为4,294,967,295或4GB(28–1)字节的BLOB列。
import java.io.*;
import java.sql.*;
public class BLOB {
public static void main(String[] args) {
Connection con=null;
PreparedStatement ps=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC","root","123456");
ps=con.prepareStatement("insert into user (id,name,info) values (?,?,?)");
ps.setInt(1,1);
ps.setString(2,"张三");
ps.setBlob(3, new FileInputStream("d:/test.jpg"));
ps.executeUpdate();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(ps!=null){
try {
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
导入成功
右键点击查看Blob的值
导入成功
ORM
ORM(Object Relationship Mapping)的基本思想
表结构跟类对应
表中字段和类的属性对应
表中记录和对象对应
首先表中有如上数据
(1)表中的记录封装到Object数组中
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo1 {
public static void main(String[] args) {
Connection con= JDBCUntil.getConnection();
PreparedStatement ps=null;
ResultSet rs=null;
try {
ps=con.prepareStatement("select name,salary,age from user where id =?");
ps.setInt(1,1);
rs=ps.executeQuery();
while(rs.next()){
Object[] objs= new Object[3]; //一个Object数组封装了一条记录的信息!
// System.out.println(rs.getString(1)+"--"+rs.getDouble(2)+"--"+rs.getInt(3));
objs[0]= rs.getObject(1);
objs[1] = rs.getObject(2);
objs[2] = rs.getObject(3);
for(Object o:objs){
System.out.println(o);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
输出结果:
张三
20000.0
12
(2)将表中的记录封装到map中
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class Demo1 {
public static void main(String[] args) {
Connection con= JDBCUntil.getConnection();
PreparedStatement ps=null;
ResultSet rs=null;
try {
ps=con.prepareStatement("select name,salary,age from user where id =?");
ps.setInt(1,1);
rs=ps.executeQuery();
while(rs.next()){
Map<Object,Object> row=new HashMap<>();
row.put("name",rs.getObject(1));
row.put("salary", rs.getObject(2));
row.put("age", rs.getObject(3));
for(Object o:row.keySet()){
System.out.println(row.get(o));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(3)将表中将表中记录封装到javabean对象中
public class User {
private int id;
private String name;
private int age;
private Double salary;
public User(int id, String name, int age, Double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public User() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
import JDBCLearn.JDBCUntil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class Demo3 {
public static void main(String[] args) {
Connection con= JDBCUntil.getConnection();
PreparedStatement ps=null;
ResultSet rs=null;
try {
ps=con.prepareStatement("select * from user where id =?");
ps.setInt(1,1);
rs=ps.executeQuery();
while(rs.next()){
User user=null; //一个Object数组封装了一条记录的信息!
int id= (int) rs.getInt(1);
String name=rs.getString(2);
int age=rs.getInt(3);
double salary=rs.getDouble(4);
user=new User(id,name,age,salary);
System.out.println(user.getName()+" "+user.getSalary());
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}