前面大概介绍了JDBC连接数据库的过程,以及怎么操作数据库,今天给大家分享JDBC怎么处理CLOB和BLOB存储图片的事情,以及JDBC怎么去处理事务。怎么在插入数据的时候生成主键返回值
一、JDBC处理CLOB和BLOB数据
1.1、JDBC处理CLOB(在MySQL中是TEXT)
环境:
create table tb_clob_test_1(id int,clob_data text); 前面使用的DButils工具类,用来获取Connection连接和关闭资源。
1)text类型也可以存储字符串
public void clobTest_1() { Connection conn = null; PreparedStatement pstmt = null; try { conn = DBUtils.getConn(); String sql = "insert into tb_clob_test(clob_data)values(?)"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, "hello world"); pstmt.execute(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtils.close(null, pstmt, conn); } }
2)数据的存入
如果数据只有ASCII,即不能有中文字符和特殊字符:
pstmt.setAsciiStream(1,x);
如果数据包含中文字符或者其他特殊字符:
File file=new File(“xxx”);
FileReader reader=new FileReader(file);
pstmt.setCharacterStream(1,reader,file.length());
pstmt.setCharacterStream(1,new FileReader("D:/java.txt"));
pstmt.setClob(1,new FileReader("D:/java.txt"));
@Test public void clobTest_2() { Connection conn = null; PreparedStatement pstmt = null; try { conn = DBUtils.getConn(); String sql = "insert into tb_clob_test(clob_data)values(?)"; pstmt = conn.prepareStatement(sql); // pstmt.setCharacterStream(1,new FileReader("D:/java.txt")); pstmt.setClob(1,new FileReader("D:/java.txt")); pstmt.execute(); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { DBUtils.close(null, pstmt, conn); } }
3)数据的获取
直接拿出字符流
public void clobSelectTest_1() { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; PrintWriter writer = null; BufferedReader bf = null; try { conn = DBUtils.getConn(); String sql = "select * from tb_clob_test where id = 4"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); writer = new PrintWriter("java.txt.bak"); while(rs.next()){ int id = rs.getInt(1); Reader reader = rs.getCharacterStream(2); bf = new BufferedReader(reader); String str = null; while ((str=bf.readLine())!=null){ writer.write(str); writer.write(" "); writer.flush(); } } pstmt.execute(); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { bf.close(); } catch (IOException e) { e.printStackTrace(); } try { writer.close(); } catch (Exception e) { e.printStackTrace(); } DBUtils.close(null, pstmt, conn); } }
先拿出Clob,然后转化成字符流
resultSet=pstmt.executeQuery(); while (res.next()) { File file = new File("note_bak.txt"); FileWriter fw = new FileWriter(file); Clob clob = resultSet.getClob(2); Reader reader = clob.getCharacterStream(); char[] cs = new char[1024]; int length = 0; while((length = reader.read(cs))!=-1){ fw.write(cs, 0, length); fw.flush(); } fw.close(); reader.close();
1.2、JDBC处理BLOB
环境:
create table tb_blob_test_1(id int,blob_data longblob);
1)存储图片
public class BlobDemo_0010 { @Test public void blobInsert_1(){ Connection conn = null; PreparedStatement pstmt = null; try { conn = DBUtils.getConn(); String sql = "insert into tb_blob_test(blob_data)values(?)"; pstmt = conn.prepareStatement(sql); pstmt.setBinaryStream(1,new FileInputStream("D:/11.jpg")); boolean execute = pstmt.execute(); System.out.println(execute); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } }
方式二:
String sql=”insert into tb_blob_test_1(blob_data) values(?)”; pstmt=conn.prepareStatement(sql); File file=new File(“xxx.jpg”); BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file)); pstmt.setBlob(2,bis); pstmt.execute();
2)从数据库中读取图片
public void blobSelect_1(){ Connection conn = null; PreparedStatement pstmt = null; try { conn = DBUtils.getConn(); String sql = "select * from tb_blob_test where id =1"; pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); rs.next(); InputStream is = rs.getBinaryStream(2); OutputStream os = new FileOutputStream("D:/blob.jpg"); byte[] bs = new byte[1024]; int len = -1; while ((len=is.read(bs))!=-1){ os.write(bs,0,len); } os.flush(); os.close(); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
二、JDBC中设置事务的隔离级别
在JDBC中一些基本的设置事务的操作
//MySQL设置事务隔离级别,一般不会再JDBC代码中设置,会直接在MySQL服务器中去设置 conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); //在JDBC设置手动提交事务 conn.setAutoCommit(false);
//设置回滚点
sp = conn.setSavepoint();
//事务回滚
conn.rollback(sp);
事务处理具体实例:
public void tx_test_1(){ Connection conn = null; PreparedStatement pstmt =null; Savepoint sp = null; try { conn = DBUtils.getConn(); //MySQL设置事务隔离级别,一般不会再JDBC代码中设置,会直接在MySQL服务器中去设置 conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); //在JDBC设置手动提交事务 conn.setAutoCommit(false); //在转账的时候,先判断源账号的余额是否大于转账金额 //判断之前先查询源账户的余额 String sql0 = "select balance from tb_account where id =1"; pstmt = conn.prepareStatement(sql0); ResultSet rs = pstmt.executeQuery(); double balance=0; if(rs.next()){ balance = rs.getDouble(1); } //转账金额 double much = 1000; //判断余额是否大于转账金额 if(balance<much){ DBUtils.close(rs,pstmt,conn); return; } sp = conn.setSavepoint(); //张三的余额减去1000 String sql1 = "update tb_account set balance=balance-1000 where id=1"; pstmt = conn.prepareStatement(sql1); pstmt.executeUpdate(); //李四的余额加上1000 String sql2 = "update tb_account set balance=balance+1000 where id=2"; // pstmt.executeUpdate(sql2);这是调用父类的方法一样可以 pstmt = conn.prepareStatement(sql2); pstmt.executeUpdate(); } catch (SQLException e) { try { // conn.rollback(); conn.rollback(sp); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { try { conn.commit(); } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } DBUtils.close(null,pstmt,conn); } }
三、生成主键返回值
环境:
create tb_pserson_1(id int primary key auto_increment,name varchar(20));
具体步骤:
String sql=”insert into tb_pserson_1(name) values(?)”; pstmt=conn. prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); pstmt.executeUpdate(); resultSet=pstmt. getGeneratedKeys();
此时的resultSet里面存放的是刚才插入的那条数据的自动生成的ID。
四、数据库元数据的查看
在我们前面使用JDBC来处理数据库的接口主要有三个,即Connection,PreparedStatement和ResultSet这三个,而对于这三个接口,还可以获取不同类型的元数据,通过这些元数据类获得一些数据库的信息。
元数据(MetaData),即定义数据的数据。打个比方,就好像我们要想搜索一首歌(歌本身是数据),而我们可以通过歌名,作者,专辑等信息来搜索,那么这些歌名,作者,专辑等等就是这首歌的元数据。因此数据库的元数据就是一些注明数据库信息的数据。
① 由Connection对象的getMetaData()方法获取的是DatabaseMetaData对象。
② 由PreparedStatement对象的getParameterMetaData ()方法获取的是ParameterMetaData对象。
③由ResultSet对象的getMetaData()方法获取的是ResultSetMetaData对象。
4.1、DatabaseMetaData
DatabaseMetaData是由Connection对象通过getMetaData方法获取而来,主要封装了是对数据库本身的一些整体综合信息。
例如数据库的产品名称,数据库的版本号,数据库的URL,是否支持事务等等,能获取的信息比较多,具体可以参考DatabaseMetaData的API文档。
DatabaseMetaData data = conn.getMetaData(); //查看当前连接中有关MySQL的系统信息,比如版本号,是否支持事务,数据库名字。
以下有一些关于DatabaseMetaData的常用方法:
·getDatabaseProductName:获取数据库的产品名称
·getDatabaseProductName:获取数据库的版本号
·getUserName:获取数据库的用户名
·getURL:获取数据库连接的URL
·getDriverName:获取数据库的驱动名称
·driverVersion:获取数据库的驱动版本号
·isReadOnly:查看数据库是否只允许读操作
·supportsTransactions:查看数据库是否支持事务
4.2、ParameterMetaData
ParameterMetaData是由PreparedStatement对象通过getParameterMetaData方法获取而来,主要是针对PreparedStatement对象和其预编译的SQL命令语句提供一些信息,
比如像”insert into account(id,name,money) values(?,?,?)”这样的预编译SQL语句,ParameterMetaData能提供占位符参数的个数,获取指定位置占位符的SQL类型等等,功能也比较多,这里不列举完,详细请看有关ParameterMetaData的API文档。
常用方法:
·getParameterCount:获取预编译SQL语句中占位符参数的个数
在我看来,ParameterMetaData对象能用的只有获取参数个数的getParameterCount()方法。
注意:ParameterMetaData许多方法MySQL并不友好支持,比如像获取指定参数的SQL类型的getParameterType方法,如果数据库驱动连接URL只是简单的“jdbc:mysql://localhost:3306/jdbcdemo”那么MyEclipse会抛出SQLException异常,
必须要将URL修改为“jdbc:mysql://localhost:3306/jdbcdemo?generateSimpleParameterMetadata=true”才行。但是像getParameterType等等与其他的方法也没多好用,因为如下面的例子,这些方法好像只会将所有的参数认为是字符串(VARCHAR)类型。
public void testParameterMetaData() throws SQLException { Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); String sql = "insert into user(id,name,age) values(?,?,?)"; st = conn.prepareStatement(sql); st.setInt(1, 1); st.setString(2, "Ding"); st.setInt(3, 25); ParameterMetaData paramMetaData = st.getParameterMetaData(); //获取参数个数 int paramCount = paramMetaData.getParameterCount(); //以字符串形式获取指定参数的SQL类型,这里有问题 String paramTypeName = paramMetaData.getParameterTypeName(1); //返回指定参数的SQL类型,以java.sql.Types类的字段表示,这里有问题 int paramType = paramMetaData.getParameterType(1); //返回指定参数类型的Java完全限定名称,这里有问题 String paramClassName = paramMetaData.getParameterClassName(1); //返回指定参数的模,,这里有问题 int paramMode = paramMetaData.getParameterMode(1); //返回指定参数的列大小,这里有问题 int precision = paramMetaData.getPrecision(1); //返回指定参数的小数点右边的位数,这里有问题 int scale = paramMetaData.getScale(1); }
注:完全限定名称,指的是该类型的Java完整名称,包括包名和类型。
结果:
因为我们的SQL语句为"insert into user(id,name,age) values(?,?,?)",而我们所有利用ParameterMetaData查询的信息除了参数个数以外,都是查询第一个参数的信息,也就是“id”列,而这个“id”列我们创建时是int整型的,
但是利用ParameterMetaData的查询结果都是显示为字符串类型,因此我对ParameterMetaData的功能产生了怀疑。
因此在以后使用参数元数据ParameterMetaData尽量只要使用其getParamterCount()方法获取参数个数,对于该对象其他方法请慎用。
4.3、ResultSetMetaData
ResultSetMetaData是由ResultSet对象通过getMetaData方法获取而来,主要是针对由数据库执行的SQL脚本命令获取的结果集对象ResultSet中提供的一些信息,
比如结果集中的列数、指定列的名称、指定列的SQL类型等等,可以说这个是对于框架来说非常重要的一个对象。关于该结果集元数据对象的其他具体功能和方法请查阅有关ResultSetMetaData的API文档。
以下有一些关于ResultSetMetaData的常用方法:
·getColumnCount:获取结果集中列项目的个数
·getColumnType:获取指定列的SQL类型对应于Java中Types类的字段
·getColumnTypeName:获取指定列的SQL类型
·getClassName:获取指定列SQL类型对应于Java中的类型(包名加类名)
实例:
数据表
create table user( id int primary key, name varchar(40), age int ); insert into user(id,name,age) values(1,'Ding',25); insert into user(id,name,age) values(2,'LRR',24);
测试
public void testResultSetMetaData() throws SQLException { Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); String sql = "select * from user"; st = conn.prepareStatement(sql); rs = st.executeQuery(); ResultSetMetaData resultMetaData = rs.getMetaData(); //获取结果集的列数 int columnCount = resultMetaData.getColumnCount(); //获取指定列的名称 String columnName = resultMetaData.getColumnName(1); //获取指定列的SQL类型对应于java.sql.Types类的字段 int columnType = resultMetaData.getColumnType(1); //获取指定列的SQL类型 String columnTypeName = resultMetaData.getColumnTypeName(1); //获取指定列SQL类型对应于Java的类型 String className= resultMetaData.getColumnClassName(1); //获取指定列所在的表的名称 String tableName = resultMetaData.getTableName(1); }