DatabaseMetaData的简单使用

article/2025/11/11 15:22:22

在看大佬写的一个导出数据库建标脚本的接口的时候,发现频频用到DataBaseMetaData这个类,之前也没有 用过这个类下的API,记录一下心得用法。

DatabaseMetaData是java.sql包中的接口,利用它可以获取我们连接到的数据库的结构、存储等很多信息;先上个API文档:
在这里插入图片描述
这英文看的是心力憔悴,直接上代码来看这个接口下面的用法:

查看数据库元数据

  @org.junit.Testpublic void getMetaData() {DataSource dataSource = new DataSource();dataSource.setUrl("jdbc:mysql://localhost:3306/mytest");dataSource.setDriverClassName("com.mysql.jdbc.Driver");//dataSource.setDriverClassName("oracle.jdbc.OracleDriver");dataSource.setUsername("root");dataSource.setPassword("root");Connection conn = null;ResultSet rs = null;try {conn = dataSource.getConnection();DatabaseMetaData dbmd = conn.getMetaData();System.out.println("数据库已知的用户: " + dbmd.getUserName());System.out.println("数据库的系统函数的逗号分隔列表: " + dbmd.getSystemFunctions());System.out.println("数据库的时间和日期函数的逗号分隔列表: " + dbmd.getTimeDateFunctions());System.out.println("数据库的字符串函数的逗号分隔列表: " + dbmd.getStringFunctions());System.out.println("数据库供应商用于 'schema' 的首选术语: " + dbmd.getSchemaTerm());System.out.println("数据库URL: " + dbmd.getURL());System.out.println("是否允许只读:" + dbmd.isReadOnly());System.out.println("数据库的产品名称:" + dbmd.getDatabaseProductName());System.out.println("数据库的版本:" + dbmd.getDatabaseProductVersion());System.out.println("驱动程序的名称:" + dbmd.getDriverName());System.out.println("驱动程序的版本:" + dbmd.getDriverVersion());System.out.println("数据库中使用的表类型");rs = dbmd.getTableTypes();while (rs.next()) {System.out.println(rs.getString("TABLE_TYPE"));}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.closeConnection(conn);JdbcUtils.closeResultSet(rs);}}

输出结果:

数据库已知的用户: root@localhost
数据库的系统函数的逗号分隔列表: DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION
数据库的时间和日期函数的逗号分隔列表: DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC
数据库的字符串函数的逗号分隔列表: ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER
数据库供应商用于 'schema' 的首选术语: 
数据库URL: jdbc:mysql://localhost:3306/mytest
是否允许只读:false
数据库的产品名称:MySQL
数据库的版本:5.7.28
驱动程序的名称:MySQL-AB JDBC Driver
驱动程序的版本:mysql-connector-java-5.1.21 ( Revision: ${bzr.revision-id} )
数据库中使用的表类型
TABLE
VIEW
LOCAL TEMPORARY

查看数据库表的元数据

通过getTables可以返回一个ResultSet里面包含着这个数据表的元数据,但是我们一开始也不知道这个rs里面有哪些属性呀,我们先遍历一下看下rs里面有哪些属性,把获取数据库的一块代码挑取出来方便后续使用:

  DataSource getSource() {DataSource dataSource = new DataSource();dataSource.setUrl("jdbc:mysql://localhost:3306/mytest");dataSource.setDriverClassName("com.mysql.jdbc.Driver");//dataSource.setDriverClassName("oracle.jdbc.OracleDriver");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;}

上测试代码:

 @org.junit.Testpublic void getTableMetaData() {DataSource dataSource = null;Connection conn = null;ResultSet rs = null;try {dataSource = getSource();conn = dataSource.getConnection();DatabaseMetaData dbmd = conn.getMetaData();//catalog 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围//schemaPattern 数据库名,对于oracle来说就用户名//tableNamePattern 表名称模式;它必须与存储在数据库中的表名称匹配,支持模糊查询,%和_连个占位符,和在数据库中占位符意义一样//types 表的类型(TABLE | VIEW)rs = conn.getMetaData().getTables(null, null, "%", new String[] { "TABLE" });//结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();for (int i = 1 ; i <= rsmd.getColumnCount(); i++ ){String column = rsmd.getColumnName(i);System.out.println(column);}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.closeConnection(conn);JdbcUtils.closeResultSet(rs);}}

输出结果(MYSQL):

TABLE_CAT
TABLE_SCHEM
TABLE_NAME
TABLE_TYPE
REMARKS

稍微解释一下这几个是什么意思:

  • TABLE_CAT String => 表类别
  • TABLE_SCHEM String => 表模式
  • TABLE_NAME String => 表名称
  • TABLE_TYPE String => 表类型
  • REMARKS String => 表备注

然后来看看我们的表中这些元数据的属性是什么吧:

  @org.junit.Testpublic void getTableMetaData() {DataSource dataSource = null;Connection conn = null;ResultSet rs = null;try {dataSource = getSource();conn = dataSource.getConnection();DatabaseMetaData dbmd = conn.getMetaData();//catalog 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围//schemaPattern 数据库名,对于oracle来说就用户名//tableNamePattern 表名称模式;它必须与存储在数据库中的表名称匹配,支持模糊查询,%和_连个占位符,和在数据库中占位符意义一样//types 表的类型(TABLE | VIEW)rs = conn.getMetaData().getTables(null, null, "%", new String[]{"TABLE"});ResultSetMetaData rsmd = rs.getMetaData();
//            for (int i = 1 ; i <= rsmd.getColumnCount(); i++ ){
//                String column = rsmd.getColumnName(i);
//                System.out.println(column);
//            }while(rs.next()) {System.out.println(rs.getString("TABLE_CAT"));System.out.println(rs.getString("TABLE_SCHEM"));System.out.println(rs.getString("TABLE_NAME"));System.out.println(rs.getString("TABLE_TYPE"));System.out.println(rs.getString("REMARKS"));}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.closeConnection(conn);JdbcUtils.closeResultSet(rs);}}

输出结果:

mytest
null
data_standard
TABLEmytest
null
eao_dem_demo
TABLEmytest
null
user_information
TABLEmytest
null
userpo
TABLE

写这个Demo的时候遇到一个小问题,关于if(rs.next())与while(rs.next()),if(rs.next())触发一次rs移动,返回true,执行方法体;while(rs.next())触发rs移动,如果返回true,则一只循环循环体内的内容;总结:if(rs.next())是取出结果集第一个,while(rs.next())是遍历结果集。

查看数据库列的元数据

跟上面一样,先看看列都有哪些元数据属性:

@org.junit.Testpublic void getColumnMetaData() {DataSource dataSource = null;Connection conn = null;ResultSet rs = null;try {dataSource = getSource();conn = dataSource.getConnection();DatabaseMetaData dbmd = conn.getMetaData();// 得到全部列名// String catalog 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围// String schemaPattern 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围// String tableNamePattern 表名称模式;它必须与存储在数据库中的表名称匹配// String columnNamePattern 列名称模式;它必须与存储在数据库中的列名称匹配// 每一行都是一个列描述rs = conn.getMetaData().getColumns(null, null, "%","%");ResultSetMetaData rsmd = rs.getMetaData();for (int i = 1 ; i <= rsmd.getColumnCount(); i++ ){String column = rsmd.getColumnName(i);System.out.println(column);}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.closeConnection(conn);JdbcUtils.closeResultSet(rs);}}

输出结果:

TABLE_CAT          
TABLE_SCHEM
TABLE_NAME
COLUMN_NAME
DATA_TYPE
TYPE_NAME
COLUMN_SIZE
BUFFER_LENGTH
DECIMAL_DIGITS
NUM_PREC_RADIX
NULLABLE
REMARKS
COLUMN_DEF
SQL_DATA_TYPE
SQL_DATETIME_SUB
CHAR_OCTET_LENGTH
ORDINAL_POSITION
IS_NULLABLE
SCOPE_CATALOG
SCOPE_SCHEMA
SCOPE_TABLE
SOURCE_DATA_TYPE
IS_AUTOINCREMENT

解释一下这些属性是什么意思:

  • TABLE_CAT:表类别(可能为空)
  • TABLE_SCHEM:表模式(可能为空)
  • TABLE_NAME:表名
  • COLUMN_NAME:列名
  • DATA_TYPE:对应的java.sql.Types的SQL类型(列类型ID)
  • TYPE_NAME:java.sql.Types类型名称(列类型名称)
  • COLUMN_SIZE:列大小
  • BUFFER_LENGTH:缓冲长度(有待验证)
  • DECIMAL_DIGITS:小数位数
  • NUM_PREC_RADIX:/基数(通常是10或2,有待验证)
  • NULLABLE:是否允许为null
  • REMARKS:列描述
  • COLUMN_DEF:默认值
  • SQL_DATA_TYPE:SQL数据类型(有待验证)
  • SQL_DATETIME_SUB:SQL时间间隔(有待验证)
  • CHAR_OCTET_LENGTH:对于 char 类型,该长度是列中的最大字节数
  • ORDINAL_POSITION:表中列的索引(从1开始)
  • IS_NULLABLE:是否允许为null,0为不允许为空,1为允许为空,2为不确定

然后再看看这些属性的输出结果,先看看我们的表结构:
在这里插入图片描述
这里是看每一列的元数据,这里一共有id,name,password,username四个:

  @org.junit.Testpublic void getColumnMetaData() {DataSource dataSource = null;Connection conn = null;ResultSet rs = null;try {dataSource = getSource();conn = dataSource.getConnection();DatabaseMetaData dbmd = conn.getMetaData();/*** 得到全部列名* @param String catalog 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围* @param String schemaPattern 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围* @param String tableNamePattern 表名称模式;它必须与存储在数据库中的表名称匹配* @param String columnNamePattern 列名称模式;它必须与存储在数据库中的列名称匹配* @return 每一行都是一个列描述* @throws SQLException 如果发生数据库访问错误*/rs = conn.getMetaData().getColumns(null, null, "user_information","%");ResultSetMetaData rsmd = rs.getMetaData();while(rs.next()){System.out.println("TABLE_CAT is :" + rs.getString("TABLE_CAT"));System.out.println("TABLE_SCHEM is :" +rs.getString("TABLE_SCHEM"));System.out.println("TABLE_NAME is :" +rs.getString("TABLE_NAME"));System.out.println("COLUMN_NAME is :" +rs.getString("COLUMN_NAME"));System.out.println("DATA_TYPE is :" +rs.getInt("DATA_TYPE"));System.out.println("TYPE_NAME is :" +rs.getString("TYPE_NAME"));System.out.println("COLUMN_SIZE is :" +rs.getInt("COLUMN_SIZE"));System.out.println("BUFFER_LENGTH is :" +rs.getInt("BUFFER_LENGTH"));System.out.println("DECIMAL_DIGITS is :" +rs.getInt("DECIMAL_DIGITS"));System.out.println("NUM_PREC_RADIX is :" +rs.getInt("NUM_PREC_RADIX"));System.out.println("NULLABLE is :" +rs.getInt("NULLABLE"));System.out.println("REMARKS is :" +rs.getString("REMARKS"));System.out.println("COLUMN_DEF is :" +rs.getString("COLUMN_DEF"));System.out.println("SQL_DATA_TYPE is :" +rs.getInt("SQL_DATA_TYPE"));System.out.println("SQL_DATETIME_SUB is :" +rs.getInt("SQL_DATETIME_SUB"));System.out.println("CHAR_OCTET_LENGTH is :" +rs.getInt("CHAR_OCTET_LENGTH"));System.out.println("ORDINAL_POSITION is :" +rs.getInt("ORDINAL_POSITION"));System.out.println("IS_NULLABLE is :" +rs.getString("IS_NULLABLE"));System.out.println("\n");}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.closeConnection(conn);JdbcUtils.closeResultSet(rs);}}

输出结果(一共四列):

TABLE_CAT is :mytest
TABLE_SCHEM is :null
TABLE_NAME is :user_information
COLUMN_NAME is :id
DATA_TYPE is :4
TYPE_NAME is :INT
COLUMN_SIZE is :10
BUFFER_LENGTH is :65535
DECIMAL_DIGITS is :0
NUM_PREC_RADIX is :10
NULLABLE is :0
REMARKS is :
COLUMN_DEF is :null
SQL_DATA_TYPE is :0
SQL_DATETIME_SUB is :0
CHAR_OCTET_LENGTH is :0
ORDINAL_POSITION is :1
IS_NULLABLE is :NOTABLE_CAT is :mytest
TABLE_SCHEM is :null
TABLE_NAME is :user_information
COLUMN_NAME is :name
DATA_TYPE is :12
TYPE_NAME is :VARCHAR
COLUMN_SIZE is :20
BUFFER_LENGTH is :65535
DECIMAL_DIGITS is :0
NUM_PREC_RADIX is :10
NULLABLE is :1
REMARKS is :
COLUMN_DEF is :null
SQL_DATA_TYPE is :0
SQL_DATETIME_SUB is :0
CHAR_OCTET_LENGTH is :20
ORDINAL_POSITION is :2
IS_NULLABLE is :YESTABLE_CAT is :mytest
TABLE_SCHEM is :null
TABLE_NAME is :user_information
COLUMN_NAME is :password
DATA_TYPE is :12
TYPE_NAME is :VARCHAR
COLUMN_SIZE is :20
BUFFER_LENGTH is :65535
DECIMAL_DIGITS is :0
NUM_PREC_RADIX is :10
NULLABLE is :1
REMARKS is :
COLUMN_DEF is :null
SQL_DATA_TYPE is :0
SQL_DATETIME_SUB is :0
CHAR_OCTET_LENGTH is :20
ORDINAL_POSITION is :3
IS_NULLABLE is :YESTABLE_CAT is :mytest
TABLE_SCHEM is :null
TABLE_NAME is :user_information
COLUMN_NAME is :username
DATA_TYPE is :12
TYPE_NAME is :VARCHAR
COLUMN_SIZE is :255
BUFFER_LENGTH is :65535
DECIMAL_DIGITS is :0
NUM_PREC_RADIX is :10
NULLABLE is :1
REMARKS is :
COLUMN_DEF is :null
SQL_DATA_TYPE is :0
SQL_DATETIME_SUB is :0
CHAR_OCTET_LENGTH is :255
ORDINAL_POSITION is :4
IS_NULLABLE is :YES

http://chatgpt.dhexx.cn/article/tM05hdZX.shtml

相关文章

DatabaseMetaData类

DatabaseMetaData类是java.sql包中的类&#xff0c;利用它可以获取我们连接到的数据库的结构、存储等很多信息。如&#xff1a; 1、数据库与用户&#xff0c;数据库标识符以及函数与存储过程。 2、数据库限制。 3、数据库支持不支持的功能。 4、架构、…

数据库之-元数据 DatabaseMetaData 初学

DatabaseMetaData和ResultSetMetaData就是两个常用的获取数据库元数据相关信息的接口&#xff0c;本文讲解DatabaseMetaData和ResultSetMetaData接口获取元数据的方法。 获取数据库的所有表&#xff1a;(以MySQL和Oracle为例&#xff0c;其他类型的数据库接触不过&#xff0c;…

php备忘录模式

CleverCode最近在看备忘录模式。 1 模式介绍 在不破坏封闭的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 2 模式中的角色 1.Originator(发起人)&#xff1a;负责创建一个备忘录Memento&…

设计模式 — 行为型模式 — 备忘录模式

目录 文章目录 目录备忘录模式应用场景代码示例 备忘录模式 备忘录模式&#xff0c;在不破坏封闭的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 简单来说&#xff0c;就是在运行过程中我们…

“备忘录模式”就这么简单

备忘录模式的官方定义&#xff1a; 在不破坏封装性的前提下&#xff0c;获取一个对象的内部状态&#xff0c;并在该对象之外保存这些状态。这样以后就可以通过该对象恢复到原先保存的状态。 大白话说&#xff1a; 一个对象中一般都封装了很多属性&#xff0c;这些属性的值会随…

(18)备忘录模式

&#xfeff;&#xfeff; &#xff08;18&#xff09;备忘录模式 定义&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 类型&#xff1a;行为类 类图&#xff1a; 我们…

Java设计模式-备忘录模式、备忘录模式应用场景是什么、又怎么使用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库Java设计模式克隆下载学习使用&#xff01; 6.11 备忘录模式 6.11.1 定义 又称快照模式&#xff0c;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存此状态&am…

C++设计模式(17)——备忘录模式

亦称&#xff1a; 快照、Snapshot、Memento 意图 备忘录模式是一种行为设计模式&#xff0c; 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 问题 假如你正在开发一款文字编辑器应用程序。 除了简单的文字编辑功能外&#xff0c; 编辑器中还要有设置文本格…

Java备忘录模式(Memento)

本文我们来介绍下java23种设计模式中的备忘录模式。 备忘录模式Memento 使用场景 录入大批人员资料。正在录入当前人资料时&#xff0c;发现上一个人录错了&#xff0c; 此时需要恢复上一个人的资料&#xff0c;再进行修改。Word文档编辑时&#xff0c;忽然电脑死机或断电&a…

Java设计模式之备忘录模式

Java设计模式之备忘录模式 1. 备忘录模式概述1.1 备忘录模式简介1.2 备忘录模式类图1.3 备忘录模式的注意事项和细节 2. 备忘录模式实现2.1 项目说明2.2 项目实现 1. 备忘录模式概述 1.1 备忘录模式简介 1.备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的…

【设计模式】备忘录模式

设计模式总结链接 备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式&#xff0c;是对象的行为模式。   备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下&#xff0c;将一个对象的状态捕捉(Capture)住&#xff…

23种设计模式——备忘录模式

目录 备忘录模式&#xff08;Memento&#xff09; UML图 示例代码 适用场景 优缺点 备忘录模式和原型模式 例子——游戏进度存档 例子——象棋中的悔棋 备忘录模式&#xff08;Memento&#xff09; 本质&#xff1a;保存和恢复内部状态 备忘录模式&#xff1a;在不破坏…

23种设计模式之---备忘录模式

前言 网上搜索备忘录设计模式&#xff0c;基本上均是在一个GoF&#xff0c;基础上衍生下来的。为了避免重复造轮子&#xff0c;这里会结合网上demo&#xff0c;和自己理解进行总结 定义&#xff1a;备忘录&#xff08;Memento&#xff09;模式又称标记&#xff08;Token&…

备忘录模式介绍

备忘录模式介绍 一、基本介绍二、代码实现三、UML类图四、备忘录模式小结其他设计模式 一、基本介绍 备忘录模式&#xff08;Memento Pattern&#xff09;属于行为型模式&#xff0c;是指在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外…

设计模式 | 备忘录模式及典型应用

本文的主要内容&#xff1a; 介绍备忘录模式示例备忘录模式总结 备忘录模式 备忘录模式经常可以遇到&#xff0c;譬如下面这些场景&#xff1a; 浏览器回退&#xff1a;浏览器一般有浏览记录&#xff0c;当我们在一个网页上点击几次链接之后&#xff0c;可在左上角点击左箭头…

设计模式之备忘录模式

一、备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象。备忘录模式属于行为型模式。 原发器(Originator)角色&#xff1a;原发器根据需要决定将自己的哪些内部状态保存到备忘录中&#xff0c;并可以使…

备忘录模式(Java)

备忘录模式&#xff08;Java&#xff09; 下面是关于我所写的所有设计模式代码&#xff08;还是建议自己手打或者想一个别的例子练习一次&#xff09; (https://github.com/lihang212010/DesignPatterns-/tree/master/designpatterns/src) 先来张百度的UML 下面是我例子的U…

撤销功能的实现——备忘录模式(二)

21.2 备忘录模式概述 备忘录模式提供了一种状态恢复的实现机制&#xff0c;使得用户可以方便地回到一个特定的历史步骤&#xff0c;当新的状态无效或者存在问题时&#xff0c;可以使用暂时存储起来的备忘录将状态复原&#xff0c;当前很多软件都提供了撤销(Undo)操作&#xff0…

18-备忘录模式

文章目录 游戏角色状态恢复问题备忘录模式基本介绍备忘录模式解决游戏角色状态回复问题备忘录模式的注意事项和细节 游戏角色状态恢复问题 游戏鱼色有攻击力和防御力&#xff0c;在大战 Boss 前保存自身的状态&#xff08;攻击力和防御力&#xff09;&#xff0c;当大战 Boss …

详解设计模式:备忘录模式

详解设计模式&#xff1a;备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;也被称为快照模式&#xff08;Snapshot Pattern&#xff09;、Token 模式&#xff08;Token Pattern&#xff09;&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。 备忘录模式…