• 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)+"	"
    47 +rs.getString(2)+"	"+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)+"	");
    48             }
    49             System.out.println();
    50             //遍历数据表
    51             rs.beforeFirst();
    52             while(rs.next())
    53             {
    54                 System.out.println(rs.getInt(1)+"	"+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
  • 相关阅读:
    netty用户退出,网络断开,重连删除用户信息
    netty的 ctx.writeAndFlush()方法
    netty实现动态定时器
    springboot java.sql.SQLException: sql injection violation, multi-statement not allow : update XXX(table)
    SpringBoot用流多次读取request请求中的数据
    mysql分组统计,按照时间排序
    Flash Player离线安装包下载指南
    maven pom.xml配置详解
    oracle 权限管理
    Oracle 表空间管理
  • 原文地址:https://www.cnblogs.com/weststar/p/12699179.html
Copyright © 2020-2023  润新知