10.6 管理结果集

目录:

一、可滚动、可更新的结果集

二、处理Blob类型数据

三、使用ResultSetMetaData分析结果集

一、可滚动、可更新的结果集

  可以使用next()、absolute()、afterLast()、previous()等方法自由移动记录指针的ResultSet被称为可滚动的结果集
  以默认方式打开的ResultSet是不可更新的,如果希望创建可更新的ResultSet,则必须在创建Statement或prepareStatement时传入额外参数。Connection在创建Statement或PrepareStatement时还可额外传入如下两个参数:
1、resultSetType:控制ResultSet的类型,该参数可以取如下三个值
(1)ResultSet.TYPE_FORWARD_ONLY:该常量控制记录指针只能向前移动。这是JDK1.4以前的默认值。
(2)ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制指针可以自由移动(可滚动结果集),但底层数据的改变不会影响ResultSet的内容。
(3)ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制记录指针可以自由记录(可滚动的结果集),而且底层数据的改变会影响ResultSet的内容。
2、resultSetConcurrency:控制ResultSet的并发类型,该参数可以接受如下两个值:
(1)ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)。
(2)ResultSet.CONCUR_UPDATABLE:该常量指示ResultSet是可更新的并发模式。
下面创建一个PreparedStatement对象,由该对象生成的ResultSet对象将是可滚动、可更新的结果集。

1 //使用Connection创建一个PreparedStatement对象
2 //传入控制结果集可滚动、可更新的参数:
3 pstmt=conn.preparedStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);

可更新的结果集还需要满足如下两个条件:
★所有数据都应该来自一个表
★选出的数据集必须包含主键列
在创建了可滚动、可更新的ResultSet时,程序可调用ResultSet的updateXxx(int columnIndex,Xxx value)方法来修改执政所指记录、特定列的值,最后调用ResultSet的updateRow()方法来提交修改。
Java 8为ResultSet添加了updateObject(String columnLable,Object x,SQLType targetSqlType)和updateObject(int columnIndex,Object x,SQLType targetSqlObject)两个默认方法,这两个方法可以直接使用Object来修改记录指针所指记录、特定列的值,其中SQLType用于指定该数据列的类型。
下面示范创建这种可滚动、可更新的结果集的方法:

 1 package section5;
 2 
 3 import java.io.FileInputStream;
 4 import java.sql.Connection;
 5 import java.sql.DriverManager;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.util.Properties;
 9 
10 public class ResultSetTest
11 {
12 private String driver;
13 private String url;
14 private String user;
15 private String pass;
16 public void initParam(String paramFile)
17 throws Exception
18 {
19 //使用Properties类加载属性
20 var props=new Properties();
21 props.load(new FileInputStream(paramFile));
22 driver=props.getProperty("driver");
23 url=props.getProperty("url");
24 user=props.getProperty("user");
25 pass=props.getProperty("pass");
26 }
27 public void query(String sql)
28 throws Exception
29 {
30 //加载驱动
31 Class.forName(driver);
32 try(
33 //创建连接
34 Connection conn= DriverManager.getConnection(url,user,pass);
35 //创建结果集可滚动、可更新的参数
36 PreparedStatement pstmt=conn.prepareStatement(sql,
37 ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
38 ResultSet rs=pstmt.executeQuery()
39 )
40 {
41 rs.last();//指针记录定位到最后一行
42 int rowCount=rs.getRow();//查询由多少条记录
43 for(var i = rowCount;i>0;i--)
44 {
45 rs.absolute(i);//将记录指针移动到第i行
46 System.out.println(rs.getString(1)+"\t"
47 +rs.getString(2)+"\t"+rs.getString(3));
48 //修改记录指针所指记录第二列的值
49 rs.updateString(2,"学生名"+i);
50 //提交修改
51 rs.updateRow();
52 }
53 }
54 }
55 public static void main(String[] args)
56 throws Exception
57 {
58 var rt=new ResultSetTest();
59 rt.initParam("src\\mysql.ini");
60 rt.query("select *from student_table;");
61 }
62 }
View Code

执行结果后查询数据表:

二、处理Blob类型数据

Blob(Binary Long Object)指的是二进制长对象,Blob列通常用于存储大文件,典型的Blob内容就是:图片、声音文件。使用Blob列可以把图片、声音等文件的二进制数据保存在数据库里,并可以从数据库里恢复指定文件。

回顾表的插入:

1 insert into teacher_table(teacher_id,teacher_name)
2 values(1,'Mike');

 试想如果有一列是Blob列,我们无法直接通过上面的SQL语句完成,因为Blob常量无法表示。

2.1 插入Blob数据

将Blob数据插入数据库需要使用PreparedStatement,该对象有一个方法:

1 setBinaryStream(int paramterIndex,inputStream x);
2 //该方法可以为指定参数传入二进制输入流

 2.2 取出Blob数据

当需要从ResultSet中取出Blob数据时,可以调用ResultSet的getBlob(int columnIndex)方法:

1 getBlob(int columnIndex);
2 //该方法返回一个Blob对象

在获取Blob对象后,Blob对象提供getBinaryStream()方法来获取该Blob数据的输入流,也可以使用Blob对象提供的getBytes()方法直接取出该Blob对象封装的二进制数据。

程序示例:

为了把图片放入数据库,先使用SQL语句创建一个数据表:

 1 mysql> use select_test;
 2 Database changed
 3 mysql> create table img_table
 4     -> (img_id int auto_increment primary key,
 5     -> img_name varchar(255),
 6     -> img_data mediumblob);
 7 Query OK, 0 rows affected (1.10 sec)
 8 
 9 mysql> desc img_table;
10 +----------+--------------+------+-----+---------+----------------+
11 | Field    | Type         | Null | Key | Default | Extra          |
12 +----------+--------------+------+-----+---------+----------------+
13 | img_id   | int(11)      | NO   | PRI | NULL    | auto_increment |
14 | img_name | varchar(255) | YES  |     | NULL    |                |
15 | img_data | mediumblob   | YES  |     | NULL    |                |
16 +----------+--------------+------+-----+---------+----------------+
17 3 rows in set (0.03 sec)

 下面程序可以实现“上传”——实际上就是将图片保存到数据库,并在右边列表框中显式图片的名字,当用户双击列表框的图片名1时,左边窗口将显式该图片——实质上就是根据选中的ID从数据库里查找图片,并将其显示出来。

  1 package section5;
  2 import java.sql.*;
  3 import javax.swing.*;
  4 import java.awt.*;
  5 import java.awt.event.*;
  6 import java.util.Properties;
  7 import java.util.ArrayList;
  8 import java.io.*;
  9 import javax.swing.filechooser.FileFilter;
 10 
 11 public class BlobTest
 12 {
 13     JFrame jf = new JFrame("图片管理程序");
 14     private static Connection conn;
 15     private static PreparedStatement insert;
 16     private static PreparedStatement query;
 17     private static PreparedStatement queryAll;
 18     // 定义一个DefaultListModel对象
 19     private DefaultListModel<ImageHolder> imageModel
 20             = new DefaultListModel<>();
 21     private JList<ImageHolder> imageList = new JList<>(imageModel);
 22     private JTextField filePath = new JTextField(26);
 23     private JButton browserBn = new JButton("...");
 24     private JButton uploadBn = new JButton("上传");
 25     private JLabel imageLabel = new JLabel();
 26     // 以当前路径创建文件选择器
 27     JFileChooser chooser = new JFileChooser(".");
 28     // 创建文件过滤器
 29     ExtensionFileFilter filter = new ExtensionFileFilter();
 30     static
 31     {
 32         try
 33         {
 34             var props = new Properties();
 35             props.load(new FileInputStream("src\\mysql.ini"));
 36             var driver = props.getProperty("driver");
 37             var url = props.getProperty("url");
 38             var user = props.getProperty("user");
 39             var pass = props.getProperty("pass");
 40 
 41             Class.forName(driver);
 42             // 获取数据库连接
 43             conn = DriverManager.getConnection(url, user, pass);
 44             // 创建执行插入的PreparedStatement对象
 45             // 该对象执行插入后可以返回自动生成的主键
 46             insert = conn.prepareStatement("insert into img_table"
 47                     + " values(null, ?, ?)", Statement.RETURN_GENERATED_KEYS);
 48             // 创建两个PreparedStatement对象,用于查询指定图片,查询所有图片
 49             query = conn.prepareStatement("select img_data from img_table"
 50                     + " where img_id = ?");
 51             queryAll = conn.prepareStatement("select img_id, "
 52                     + "img_name from img_table");
 53         }
 54         catch (Exception e)
 55         {
 56             e.printStackTrace();
 57         }
 58     }
 59     public void init() throws SQLException
 60     {
 61         // -------初始化文件选择器--------
 62         filter.addExtension("jpg");
 63         filter.addExtension("jpeg");
 64         filter.addExtension("gif");
 65         filter.addExtension("png");
 66         filter.setDescription("图片文件(*.jpg, *.jpeg, *.gif, *.png)");
 67         chooser.addChoosableFileFilter(filter);
 68         // 禁止“文件类型”下拉列表中显示“所有文件”选项
 69         chooser.setAcceptAllFileFilterUsed(false);
 70         // ---------初始化程序界面---------
 71         fillListModel();
 72         filePath.setEditable(false);
 73         // 只能单选
 74         imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 75         var jp = new JPanel();
 76         jp.add(filePath);
 77         jp.add(browserBn);
 78         browserBn.addActionListener(event -> {
 79             // 显示文件对话框
 80             int result = chooser.showDialog(jf, "浏览图片文件上传");
 81             // 如果用户选择了APPROVE(赞同)按钮,即打开,保存等效按钮
 82             if (result == JFileChooser.APPROVE_OPTION)
 83             {
 84                 filePath.setText(chooser.getSelectedFile().getPath());
 85             }
 86         });
 87         jp.add(uploadBn);
 88         uploadBn.addActionListener(avt -> {
 89             // 如果上传文件的文本框有内容
 90             if (filePath.getText().trim().length() > 0)
 91             {
 92                 // 将指定文件保存到数据库
 93                 upload(filePath.getText());
 94                 // 清空文本框内容
 95                 filePath.setText("");
 96             }
 97         });
 98         var left = new JPanel();
 99         left.setLayout(new BorderLayout());
100         left.add(new JScrollPane(imageLabel), BorderLayout.CENTER);
101         left.add(jp, BorderLayout.SOUTH);
102         jf.add(left);
103         imageList.setFixedCellWidth(160);
104         jf.add(new JScrollPane(imageList), BorderLayout.EAST);
105         imageList.addMouseListener(new MouseAdapter()
106         {
107             public void mouseClicked(MouseEvent e)
108             {
109                 // 如果鼠标双击
110                 if (e.getClickCount() >= 2)
111                 {
112                     // 取出选中的List项
113                     ImageHolder cur = (ImageHolder) imageList.
114                             getSelectedValue();
115                     try
116                     {
117                         // 显示选中项对应的Image
118                         showImage(cur.getId());
119                     }
120                     catch (SQLException sqle)
121                     {
122                         sqle.printStackTrace();
123                     }
124                 }
125             }
126         });
127         jf.setSize(620, 400);
128         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
129         jf.setVisible(true);
130     }
131     // ----------查找img_table填充ListModel----------
132     public void fillListModel() throws SQLException
133     {
134         try (
135                 // 执行查询
136                 ResultSet rs = queryAll.executeQuery())
137         {
138             // 先清除所有元素
139             imageModel.clear();
140             // 把查询的全部记录添加到ListModel中
141             while (rs.next())
142             {
143                 imageModel.addElement(new ImageHolder(rs.getInt(1),
144                         rs.getString(2)));
145             }
146         }
147     }
148     // ---------将指定图片放入数据库---------
149     public void upload(String fileName)
150     {
151         // 截取文件名
152         String imageName = fileName.substring(fileName.lastIndexOf('\\')
153                 + 1, fileName.lastIndexOf('.'));
154         var f = new File(fileName);
155         try (
156                 var is = new FileInputStream(f))
157         {
158             // 设置图片名参数
159             insert.setString(1, imageName);
160             // 设置二进制流参数
161             insert.setBinaryStream(2, is, (int) f.length());
162             int affect = insert.executeUpdate();
163             if (affect == 1)
164             {
165                 // 重新更新ListModel,将会让JList显示最新的图片列表
166                 fillListModel();
167             }
168         }
169         catch (Exception e)
170         {
171             e.printStackTrace();
172         }
173     }
174     // ---------根据图片ID来显示图片----------
175     public void showImage(int id) throws SQLException
176     {
177         // 设置参数
178         query.setInt(1, id);
179         try (
180                 // 执行查询
181                 ResultSet rs = query.executeQuery())
182         {
183             if (rs.next())
184             {
185                 // 取出Blob列
186                 Blob imgBlob = rs.getBlob(1);
187                 // 取出Blob列里的数据
188                 var icon = new ImageIcon(imgBlob.getBytes(1L, (int) imgBlob.length()));
189                 imageLabel.setIcon(icon);
190             }
191         }
192     }
193     public static void main(String[] args) throws SQLException
194     {
195         new BlobTest().init();
196     }
197 }
198 // 创建FileFilter的子类,用以实现文件过滤功能
199 class ExtensionFileFilter extends FileFilter
200 {
201     private String description = "";
202     private ArrayList<String> extensions = new ArrayList<>();
203     // 自定义方法,用于添加文件扩展名
204     public void addExtension(String extension)
205     {
206         if (!extension.startsWith("."))
207         {
208             extension = "." + extension;
209             extensions.add(extension.toLowerCase());
210         }
211     }
212     // 用于设置该文件过滤器的描述文本
213     public void setDescription(String aDescription)
214     {
215         description = aDescription;
216     }
217     // 继承FileFilter类必须实现的抽象方法,返回该文件过滤器的描述文本
218     public String getDescription()
219     {
220         return description;
221     }
222     // 继承FileFilter类必须实现的抽象方法,判断该文件过滤器是否接受该文件
223     public boolean accept(File f)
224     {
225         // 如果该文件是路径,接受该文件
226         if (f.isDirectory()) return true;
227         // 将文件名转为小写(全部转为小写后比较,用于忽略文件名大小写)
228         String name = f.getName().toLowerCase();
229         // 遍历所有可接受的扩展名,如果扩展名相同,该文件就可接受
230         for (var extension : extensions)
231         {
232             if (name.endsWith(extension))
233             {
234                 return true;
235             }
236         }
237         return false;
238     }
239 }
240 // 创建一个ImageHolder类,用于封装图片名、图片ID
241 class ImageHolder
242 {
243     // 封装图片的ID
244     private int id;
245     // 封装图片的名字
246     private String name;
247     public ImageHolder(){}
248     public ImageHolder(int id, String name)
249     {
250         this.id = id;
251         this.name = name;
252     }
253     // id的setter和getter方法
254     public void setId(int id)
255     {
256         this.id = id;
257     }
258     public int getId()
259     {
260         return this.id;
261     }
262     // name的setter和getter方法
263     public void setName(String name)
264     {
265         this.name = name;
266     }
267     public String getName()
268     {
269         return this.name;
270     }
271     // 重写toString()方法,返回图片名
272     public String toString()
273     {
274         return name;
275     }
276 }
View Code

三、使用ResultSetMetaData分析结果集

提示:MetaData意思就是元数据,即描述其他数据的数据,因此ResultSetMetaData封装了描述ResultSet对象的数据。

ResultSet里包含一个getMetaData()方法,该方法返回改ResultSetMetaData对象。通过ResultSetMetaData对象提供的大量方法来返回ResultSet的描述信息:

(1)int getColumnCount():返回该ResultSet列数量。

(2)String getColumnName(int column):返回指定索引的列类型。

(3)int getColumnType(int column):返回指定索引的列类型。

ResultSet里有一个方法返回记录条数:

(1)getRow():返回数据表的记录指针前面的记录条数。先执行ResultSet的方法last()将记录指针移到最后。

 1 package section5;
 2 
 3 import java.io.FileInputStream;
 4 import java.sql.Connection;
 5 import java.sql.DriverManager;
 6 import java.sql.ResultSet;
 7 import java.sql.ResultSetMetaData;
 8 import java.util.Properties;
 9 
10 public class MetaDataTest
11 {
12     private String driver;
13     private String url;
14     private String user;
15     private String pass;
16 
17     public void initParam(String fileName)
18         throws Exception
19     {
20         //使用Properties类加载属性
21         Properties props=new Properties();
22         props.load(new FileInputStream(fileName));
23         driver=props.getProperty("driver");
24         url=props.getProperty("url");
25         user=props.getProperty("user");
26         pass=props.getProperty("pass");
27     }
28     public void queryMetaData(String sql)
29         throws Exception
30     {
31         //加载驱动
32         Class.forName(driver);
33         try(
34                 //获取连接
35                 Connection conn=DriverManager.getConnection(url,user,pass);
36                 var cstmt=conn.createStatement();
37                 ResultSet rs=cstmt.executeQuery(sql)
38                 )
39         {
40             rs.last();
41             ResultSetMetaData rsmd=rs.getMetaData();
42             int columns=rsmd.getColumnCount();
43             System.out.println("记录条数:"+rs.getRow());
44             System.out.println("数据表的列数:"+columns);
45             for(int i=1;i<=columns;i++)
46             {
47                 System.out.print(i+":"+rsmd.getColumnName(i)+"\t");
48             }
49             System.out.println();
50             //遍历数据表
51             rs.beforeFirst();
52             while(rs.next())
53             {
54                 System.out.println(rs.getInt(1)+"\t"+rs.getString(2));
55             }
56         }
57     }
58     public static void main(String[] args)
59             throws Exception
60     {
61         var mdt=new MetaDataTest();
62         mdt.initParam("src\\mysql.ini");
63         mdt.queryMetaData("select * from teacher_table;");
64 
65     }
66 }
67 执行结果:
68 记录条数:3
69 数据表的列数:2
70 1:teacher_id    2:teacher_name    
71 1    Yeeku
72 2    Leegang
73 3    Martine
74 
75 Process finished with exit code 0
View Code

猜你喜欢

转载自www.cnblogs.com/weststar/p/12699179.html