第30次文章:文本大对象+ORM
- 2019 年 10 月 8 日
- 筆記
本周主要介绍JDBC中的两个文本大对象CLOB和BLOB,并根据前面在JDBC中编程的分析,封装了一个连接数据库和关闭流操作的工具类JDBCUtil。最后涉及了一点数据库与程序设计对象之间的对应关系ORM。
一、文本大对象的操作
大字段有些特殊,不同的数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的。而非一般的字段,一次即可读出数据。
1、CLOB(Character Large Object)
(1)基本概念
-用于存储大量的文本数据
(2)Mysql中相关类型
-TINYTEXT最大长度为255(2^[8]-1)字符的TEXT列
-TEXT[(M)]最大长度为65535(2^[16]-1)字符的TEXT列。
-MEDIUMTEXT最大长度为16777215(2^[24]-1)字符的TEXT列。
-LONGTEXT最大长度为4294967295或4GB(2^[32]-1)字符的TEXT列。
2、BOLB(Binary Large Object)
(1)基本概念
-同于存储大量的二进制数据
(2)Mysql中相关类型
-TINYBLOB最大长度为255(2^[8]-1)字符的BLOB列
-BLOB[(M)]最大长度为65535(2^[16]-1)字符的BLOB列。
-MEDIUMBLOB最大长度为16777215(2^[24]-1)字符的BLOB列。
-LONGBLOB最大长度为4294967295或4GB(2^[32]-1)字符的BLOB列。
3、两者的操作流程
CLOB和BLOB两者的主要区别就在于文本数据的字符流和二进制数据的字节流之间的区别。所以我们只对其中CLOB进行演示就好啦~BLOB与之类似。
为了我们插入文本大对象,我们在表格设计的过程中,再增加一项myInfo属性,数据类型为“text”,主要用于接收来自外部的CLOB对象。

具体实现如下:
import com.mysql.jdbc.Connection; /** * 测试时CLOB 文本大对象的使用 * 包含:将字符串、文件内容插入数据库中的CLOB字段、将CLOB字段值取出来的操作。 */ public class Demo09 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; Reader r = null; try { //加载驱动类 Class.forName("com.mysql.jdbc.Driver"); conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456"); //插入操作 // ps = conn.prepareStatement("insert into t_user (username,myInfo) values (?,?)"); // ps.setString(1, "peng1"); // ps.setClob(2, new FileReader(new File("G:\java学习\test\merge.txt")));//通过传输文本文件的方式 // ps.setClob(2, new BufferedReader(new InputStreamReader(new ByteArrayInputStream("hello world".getBytes()) )));//直接传入字符串的方式 //取出操作 String sql = "select * from t_user where id=?"; ps = conn.prepareStatement(sql); ps.setObject(1, 8012); rs = ps.executeQuery(); while(rs.next()) { Clob c= rs.getClob("myInfo"); r = c.getCharacterStream(); int temp = 0; while((temp = r.read()) != -1) { System.out.print((char)temp); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }finally { try { if(r != null) { r.close(); } } catch (Exception e) { e.printStackTrace(); } try { if(rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }
结果图:

tips:
1.对比之前简单的数据插入和取出操作,最大的差别就在于流处理。无论是输入数据setClob和取出数据之后的输出,我们都是按照之前学习的IO流的内容进行操作。其他的内容没有什么明显的差别。
2.在插入操作过程中,我们给出了调用文本插入和普通的字符串插入两种方式,都是基于流处理的操作,进行传输数据。
4、简单封装JDBCUtil工具包
在之前的所有的数据库操作中,我们都会涉及到数据库连接以及关闭流的操作,为了便于后续的操作,我们可以简单的将其封装为一个工具包。
package com.peng.jdbc; import java.io.IOException; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import com.mysql.jdbc.Connection; /** * 测试JDBC工具类 */ public class JDBCUtil { static Properties pros ; /** * 加载配置文件 */ static { pros = new Properties(); try { pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties")); } catch (IOException e) { e.printStackTrace(); } } /** * 加载数据库 * @return */ public static Connection getConnetion(){ try { Class.forName(pros.getProperty("mysqlDriver")); return (Connection) DriverManager.getConnection(pros.getProperty("mysqlURL"), pros.getProperty("mysqlUser"), pros.getProperty("mysqlPwd")); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 关闭流 * @param rs * @param ps * @param conn */ public static void close(ResultSet rs,Statement ps,Connection conn) { try { if(rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
tips:在实际的使用过程中,我们一般将自己的数据库用户名以及密码写入一个配置文件properties中,在实际使用的这些信息的时候,直接从配置文件中调用就会更加方便和安全。
简单的测试一下我们封装的工具类:
import com.mysql.jdbc.Connection; /** * 测试JDBCUtil工具类 */ public class Demo11 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null;; try { //加载驱动类 conn = JDBCUtil.getConnetion(); System.out.println("建立连接成功!"); } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtil.close(rs, ps, conn); } } }
查看一下结果:

二、ORM(Object Relationship Mapping)基本思想
1、ORM的基本思想
(1)表结构和类结构对应:表中字段和类的属性对应;表中记录和对象对应;
(2)让Javabean的属性名与类型尽量与数据库保持一致!
(3)一条记录对应一个对象。将查询到的对象放到容器中(List,Set,Map)
2、封装的常见思路
在数据库与表结构的对应过程中,我们一般有如下几种封装思路:
(1)将表中的一条记录封装到Object数组中
(2)将表中的一条记录封装到map中
(3)将表中的一条记录封装到javabean对象中
在封装每一条记录之后,我们可以将每一条记录作为一个整体,然后重新将每条记录存放在容器中,如此便形成了一个容器与表结构的一一对应关系。下面我们以将每条记录封装在Javabean中为例,进行简单了解。
/** * 使用JavaBean来封装一条记录 * 使用list<JavaBean>存储多条记录 */ public class Demo03 { /** * 仅封装一条记录 */ public static void test01() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; Emp emp = new Emp(); try { conn = JDBCUtil.getConnetion(); String sql = "select empname,salary,age from emp where id=?"; ps = conn.prepareStatement(sql); ps.setObject(1, 1); rs = ps.executeQuery(); while(rs.next()) { emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age")); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } //一个emp对应一条记录 System.out.println(emp.getEmpname()+"-"+emp.getSalary()+"-"+emp.getAge()); } /** * 在list中封装多条记录,每个Javabean代表一条记录 */ public static void test02() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Emp> list = new ArrayList<Emp>(); try { conn = JDBCUtil.getConnetion(); String sql = "select empname,salary,age from emp where id>?"; ps = conn.prepareStatement(sql); ps.setObject(1, 1); rs = ps.executeQuery(); while(rs.next()) { Emp emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age")); list.add(emp);//使用链表存放多条记录 } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } //list对应整张表,一个Javabean对应一条记录 for(Emp temp:list) { System.out.println(temp.getEmpname()+"-"+temp.getSalary()+"-"+temp.getAge()); } } /** * 在Map中封装多条记录,每个Javabean代表一条记录 */ public static void test03() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; Map<String,Emp> map = new HashMap<String,Emp>(); try { conn = JDBCUtil.getConnetion(); String sql = "select empname,salary,age from emp where id>?"; ps = conn.prepareStatement(sql); ps.setObject(1, 1); rs = ps.executeQuery(); while(rs.next()) { Emp emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age")); map.put(rs.getString("empname"),emp);//使用链表存放多条记录 } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } //map对应整张表,一个Javabean对应一条记录 for(String empName:map.keySet()) { System.out.println(map.get(empName).getEmpname()+"-"+map.get(empName).getSalary()+"-"+map.get(empName).getAge()); } } public static void main(String[] args) { test01(); System.out.println("##################"); test02(); System.out.println("##################"); test03(); } }
结果:

tips:
在整个程序开始之前,我们先创建一个Emp类(属于Javabean类),用于后续每条记录的存储。
1.在test01中,我们以id作为索引目标,仅筛选出一条记录,利用Emp的带参构造器,直接在创建新的对象的时候,将我们需要存储的参数传递进去。在输出的时候即可根据Emp内部属性的set和get方法获取相关的值,然后进行调用。
2.在test02中,直接利用list的add方法,将多条记录封装到了list中;在test03中,使用map,以empname作为键,以emp对象作为值,进行存储。
3、总结
在三种存储方式中,一般都会选择以Javabean的方式封装每一条记录。可以做到见名知意的效果,提高程序的阅读性。ORM的基本思想是为了提供一个程序和数据库表格的对应关系,深入理解每一条记录在程序内部的存储与封装,对于我们的学习很有帮助。