JDBC的使用(一)

一、JDBC 概述

1.1 持久化概述

持久化(persistence): 把内存中的数据保存到可掉电式存储设备 (硬盘、U盘等) 中以供之后使用。

大多数企业级应用,数据持久化是将数据保存到各种关系数据库, 而在 Java中,数据库存取技术只能通过 JDBC 来访问数据库。 JDBC  Java 语言访问数据库的基石,其他技术都是对 JDBC 的封装.

1.2 JDBC 概述

JDBC 介绍

 JDBCJava DataBase Connectivity Java 数据库连接)是一种用于执行 SQL 语句的 Java API可以为多种关系型数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。

JDBC 本质

 其实就是Java 官方提供的一套规范(接口),帮助开发人员快速实现不同关系型数据库的连接。

总结 : JDBC 本身是 Java 连接数据库的标准, Java 编写的一组接口组成,接口的实现由各个数据库厂商来完成.

二、JDBC 快速入门

2.1 环境准备

  1. 拷贝 MySQL  JDBC 驱动, Java 项目中: mysql-connector-java-5.1.26-bin.jar

注意:  jar ,不是 zip .

        2.选择 jar, jar 引用到 classpath 路径. idea 项目中创建一个目录 lib

右键 lib 目录,点 Add as Library...

2.2 JDBC 开发口诀

  1. 载注册驱动.
  2. 获取接对象.
  3. 创建/获取句对象.
  4. SQL语句.
  5. 放资源.

三、功能类详解

3.1 DriverManager

DriverManager : 驱动管理对象,主要用于加载注册关系型数据库的 Driver 类以及获取和关系型数据库的连接对象

  1. 加载注册驱动

注册给定的驱动对象:static void registerDriver(Driver driver);

写法:Class.forName("com.mysql.jdbc.Driver"); com.mysql.jdbc.Driver 类中存在静态代码快

1.  com.mysql.jdbc.Driver 这一份字节码加载进 JVM.

字节码被加载进JVM,就会执行其静态代码块.而其底层的静态代码块在完成注册驱动工作,将驱动注册到DriverManger .

注意: Java6 开始,JDBC4.0 有一个新特性-无需加载注册驱动.

 jar 包中存在一个java.sql.Driver 配置文件。此文件已经包含 com.mysql.jdbc.Driver 驱动名称。 程序会自动从 META-INF/services/java.sql.Driver 去读取当前的驱动类的全限定名,

以目前写不写加载注册驱动都没问题,但是 web 项目必须写上加载注册驱动代码,否则无法连接数据库。

  1. 获取连接对象

获取连接对象:static Connection getConnection(String url,String username,String password);

 参数

url :指定连接某一个数据库的路径,语法:

url=jdbc:mysql://localhost:3306/jdbcdemo

MySQL url: 如果连接的是本机的 MySQL,并且端口是默认 3306 ,则可以简写:

url=jdbc:mysql:///jdbcdemo

  password :连接数据库的密码

3.2 Connection

Connection :关系型数据库连接对象,相当于 Java 程序和数据库的通信桥梁

  1. 获取执行语句对象

获取静态语句执行对象: Statement createStatement();

获取预编译语句执行对象: PreparedStatement prepareStatement(String sql);

  1. 释放资源

关闭连接对象: void close();

  1. 事务

3.3 Statement

Statement:静态SQL语句执行对象,用于执行字符串的 SQL 语句

1. 执行 DML / DDL 语句 : int executeUpdate(String sql);

 返回值 : DML 受影响的行数,DDL 则返回 0

参数:insertupdatedeletecreate语句

2. 执行 DQL 语句:ResuleSet executeQuery(String sql);

 返回值:执行查询之后的结果数据

参数:select 语句

  1. 释放资源

关闭 Statement 对象 :void close();

四、DAO 思想

4.1 DAO 引入

在没有 DAO 的时候,我们的代码存在大量的重复。

4.2 DAO 介绍和方法设计

DAO(Data Access Object) 数据访问对象是一个面向对象数据库接口. 顾名思义就是与数据库打交道,将所有对数据源的访问操作抽象封装在一个公共 API 中。

DAO 中的主要操作: 增删改查(CRUD). 引入 DAO 之后,此时设计如下图。

DAO 作为组件,主要的是方法的设计,而方法设计需要注意什么呢?

  1. 在保存功能中,调用者需要传递多个参数进来,然后把这些数据保存到数据库中
  2. 在查询功能中,结果集的每行数据有多个列的值,然后把这些数据返回给调用者

意识: 在开发过程中,如果遇到需要传递的数据有多个的时候,通常需要使用 JavaBean 对其进行封装最终方法设计如下:

  • //调用者将需要保存的数据封装到Student对象中,然后传递进来

2   void save(Student stu)

3   //在查询之后,将每行数据封装到Student对象中,再返回给调用者

4   Student selectOne(long id);

4.3 DAO层开发规范

DAO 其实是一个组件(可以重复使用),包括:

分包规范: 域名倒写.项目模块名.组件; cn.wolfcode.pss.util; // 存放工具类 StringUtil cn.wolfcode.pss.domain; //pss模块的domain,模型对象.(Student) cn.wolfcode.pss.dao; //pss模块的dao接口. cn.wolfcode.pss.dao.impl; //pss模块的dao接口的实现类. cn.wolfcode.pss.test; // 暂时存储DAO的测试类,以后的测试类不应该放这里.

命名规范:

以下的 Xxx 表示一个模型对象,比如 Employee,Department,Student

DAO 接口 : 表示对某个模型的 CRUD 操作做规范,以 I 开头,interface

例: IEmployeeDAO/IStudentDAO

  DAO 实现类: 表示对某个 DAO 接口的实现

标准:XxxDAOImpl

例:EmployeeDAOImpl/StudentDAOImpl

  DAO 测试类: 测试 DAO 组件中的所有方法

标准:XxxDAOTest: XxxDAO 组件的测试类,

例:EmployeeDAOTest,StudentDAOTest

开发建议: 面向接口编程,声明 DAO 对象 传统的做法 : EmployeeDAOImpl dao = new

EmployeeDAOImpl(); 面向接口编程 : IEmployeeDAO dao = new EmployeeDAOImpl();

把实现类赋给接口类型,体现多态的特性:可以屏蔽不同子类之间实现的差异.

4.4 根据 DAO 规范搭建项目

4.4.1 步骤

  1. 创建项目
  2. 导入数据库驱动包
  3. 创建表和模型包以及模型对象 (domain/Student)
  4. 创建 DAO 包和 DAO 接口,设计 DAO 接口方法 (dao/IStudentDAO)
  5. 创建 DAO 实现包,实现 DAO 接口(dao.impl/StudentDAOImpl)
  6. 创建测试目录,生成测试类和方法(test/StudentDAOTest)
  7. 书写实现,实现一个方法测试一个方法并且测试通过

4.4.2 测试先行

public class StudentDAOTest {

private IStudentDAO studetDAO = new StudentDAOImpl();

@Test

public void insert() {

Student stu = new Student(null,"小明","ming@",18);

studetDAO.insert(stu);

}

@Test

public void delete() {

studetDAO.delete(2L);

}

@Test

public void update() {

Student stu = new Student(1L,"小明","ming@",19);

studetDAO.update(stu);

}

@Test

public void selectOne() {

Student stu = studetDAO.selectOne(1L);

System.out.println(stu);

}

@Test

public void selectList() {

List<Student> list = studetDAO.selectList();

for (Student stu:list) {

}

}

}

4.4.3 DAO 之保存操作

public void insert(Student stu) {

String sql = "INSERT INTO t_student(name,email,age) VALUES('" + stu.getName() + "','"

+ stu.getEmail() + "',"

+ stu.getAge() + ")";

System.out.println(sql);

Connection conn = null;

Statement st = null;

try {

// 1 加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

// 2 获取连接对象

conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "admin");// 3 获取语句对象

st = conn.createStatement();

// 4 执行sql 语句

st.executeUpdate(sql);

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (st != null) {

st.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

try {

if (conn != null) {

conn.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

}

}

在完成保存的过程中,执行 SQL 需要的参数是调用者传递进来的,所以需要将其拼接到 SQL 里面

String sql = "INSERT INTO t_student(name,email,age) VALUES('" + stu.getName() + "','"

  • stu.getEmail() + "',"
  • stu.getAge() + ")";

System.out.println(sql);

可以看出,这里的拼接操作极其恶心, 容易错,还不容易发现,拼接多了语义很不清晰,所以这里需要优化(PreparedStatement

伍、预编译语句对象

5.1 预编译语句对象简介

PreparedStatement 接口:  Statement 接口的子接口, 享有 Statement 中的方法.

使用的预编译语句对象,sql 语句中使用 ? 来作为值的占位符.

5.2 API 详解

Connection API

PreparedStatement conn对象的.prepareStatement(String sql)

PreparedStatement API

// 常用方法:

void setXxx(int parameterIndex,Xxx value); //设置第几个占位符的真正参数值.

// Xxx 表示数据类型,比如 String,int,long,Date.

 void setObject(int parameterIndex, Object x); //设置第几个占位符的真正参数值. 5

  int executeUpdate(); //执行DDL/DML语句. 注意:没有参数

// 若当前 SQL DDL语句,则返回 0.

// 若当前 SQL DML语句,则返回受影响的行数.

   ResultSet executeQuery(); //执行DQL语句,返回结果集.

close(); //释放资源

有了 PreparedStatement 就可以使用占位符 ? 来代替拼接,这样语义更加清晰,数据设置也很清晰,所以以后都使用 PreparedStatement 预编译语句对象。

5.3 插入功能优化

调整之后的插入操作:

public void insert(Student stu) {

String sql = "INSERT INTO t_student(name,email,age) VALUES(?,?,?)";

System.out.println(sql);

// 贾琏欲执事

Connection conn = null;

PreparedStatement pst = null;

try {

// 1 加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

// 2 获取连接对象

conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "admin");

// 3 获取预编译语句对象

pst = conn.prepareStatement(sql);

// sql 的? 设置数据

pst.setObject(1,stu.getName());

pst.setObject(2,stu.getEmail());

pst.setObject(3,stu.getAge());

// 4 执行sql 语句

pst.executeUpdate();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (pst != null) {

pst.close();

}

} catch (SQLException e) {

 e.printStackTrace();

}

try {

if (conn != null) {

conn.close();

}

} catch (SQLException e) {

 e.printStackTrace();

}

}

}

六、基于 JDBC  DAO 案例

6.1 DAO 之更新、删除

更新和删除都属于 DML 操作,它们和插入的不同仅仅就 SQL 语句不同而已,其他的都是相同的。

DML 操作模板:

//String sql = "INSERT INTO t_student(name,email,age) VALUES(?,?,?)"; //String sql = "DELETE FROM t_student WHERE id=?";

String sql = "UPDATE t student SET name=?,email=?,age=? WHERE id=?";

Connection conn = null;

PreparedStatement pst = null;

try {

//1 加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2 获取连接对象

conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "admin");

//3 获取预编译语句对象

pst = conn.prepareStatement(sql);

//给sql 的? 设置数据

pst.setString(1, stu.getName());

pst.setString(2, stu.getEmail());

pst.setInt(3, stu.getAge());

pst.setLong(1,id);

pst.setString(1,stu.getName());

pst.setString(2,stu.getEmail());

pst.setInt(3,stu.getAge());

pst.setLong(4,stu.getId());

// 4 执行sql 语句

pst.executeUpdate();

} catch (Exception e) { e.printStackTrace();

} finally {

try {

if (pst != null) {

pst.close();

}

} catch (SQLException e) { e.printStackTrace();

}

try {

if (conn != null) {

conn.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

}

在此 DML 操作就完成了,目前就差 DQL 了。

6.2 DAO 之查询操作

DQL 操作和DML 操作的不同之处是 DQL 需要获取返回的数据,而这些数据都被存在一个叫 ResultSet 的对象中

ResultSet Statement对象的 executeQuery(String sql); //执行DQL语句,返回结果集.

ResultSet PreparedStatement对象的 executeQuery(); //执行DQL语句,返回结果集.

6.2.1_查询结果对象

ResultSet 接口: 通过执行 DQL 语句查询之后的结果对象.

ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集

// 常用方法:select id,name,age

boolean next(); //判断当前光标是否能向下移动,能向下移动返回true,并同时将光标移动到下一行Xxx getXxx(int columnIndex);  //取出当前光标所在行的第columnIndex列的数据(columnIndex 1开始算).

Xxx getXxx(String columnName);//取出当前光标所在行的列名为columnName列的数,columnName可以是别名.

// Xxx 表示数据类型,比如String,int,long,Date. 推荐使用列名来取数据.

 close();// 释放资源

ResultSet 中存的数据则为查询出来的结果,这个结果就是一张表的结果。

id

name

email

age

1

小明

xiao@

18

2

小东

dong@

18

而我们要做的就是从 ResultSet 中来取出这些数据。

操作步骤

先取行: 默认光标在第一行,则为标题行(数据)使用 ResultSet  next 方法完成

再取列: id name age

// 取出当前光标所在行的第columnIndex列的数据(columnIndex  1 开始算).

Xxx getXxx(int columnIndex);  // 索引可能会变化,所以不建议使用

// 取出当前光标所在行的列名为columnName列的数据,columnName可以是别名.(推荐)

 Xxx getXxx(String columnName);

七、重构设计

 DAO 的实现过程中,发现释放资源的代码非常恶心,而且还需要反复编写,这种代码我们通常可以抽取到工具类中: JDBCUtil

7.1 抽取 JDBCUtil 工具类

// JDBCUtil.java

  // 释放资源

public static void close(Connection conn, Statement pst, ResultSet rs) {

try {

if (rs != null) {

rs.close();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放资源

try {

if (pst != null) {

pst.close();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (conn != null) {

conn.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

在获取连接的过程,需要指定连接的信息: 驱动类的全限定名 / url / 用户名 /密码(连接数据库的四要素), 但是每次都需要编写对应的字符串,麻烦,重复,也容易错。

将获取连接对象的操作抽取到工具类中,统一编写连接数据库的信息

//JDBCUtil.java

public static Connection getConnection() throws Exception {

// 加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//获取连接对象

return DriverManager.getConnection("jdbc:mysql://localhost:3306/javaweb", "root", "admin");

 }

加载注册驱动在整个程序只需要执行一次,所以将加载的代码放到静态代码块中

//JDBCUtil.java

 static {

// 加载注册驱动

// 该操作,在整个程序中只需要执行一次

try {

Class.forName("com.mysql.jdbc.Driver");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

 }

上面的代码中,我们是将连接数据库的信息编写在 Java 代码中的,这当中包括数据库的用户名和密码Java代码会编译成字节码文件,然后把字节码文件交给用户去使用,当用户需要修改数据库密码时,此时不方便

问题: 硬编码

解决方案: 配置文件 properties(key-value) || xml

由于四要素是key=value 格式,所有选择使用 properties

7.2_抽取db.properties

driverClassName=com.mysql.jdbc.Driver

 url=jdbc:mysql://localhost:3306/javaweb 4 username=root

 password=admin

将文件中的数据加载到内存中的 Properties 对象,然后再从 Properties 中获取数据,设置给 JDBC

// JDBCUtil.java

private JdbcUtil() {}

  private static Properties p;

 static {

// 加载注册驱动

// 该操作,在整个程序中只需要执行一次

try {

// properties配置文件只需要加载一次

InputStream in = Thread.currentThread().getContextClassLoader()

getResourceAsStream("db.properties");

p = new Properties();

p.load(in)

Class.forName(p.getProperty("driverClassName"));

} catch (Exception e) {

e.printStackTrace();

}

}

// 获取连接对象

public static Connection getConnection() throws Exception {

// 获取连接对象

return DriverManager.getConnection(

p.getProperty("url"),

p.getProperty("username"),

p.getProperty("password"));

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/37823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

41.HOOK引擎设计原理

上一个内容&#xff1a;41.HOOK引擎设计原理 在一个游戏里通过hook来完成各种各样的功能&#xff0c;比如hook点是a、b、c&#xff0c;然后a点会有它自己所需要的hook逻辑&#xff0c;b、c也是有它们自己的hook逻辑&#xff08;hook逻辑指的是hook之后要做的事&#xff09;&am…

算法设计与分析--近似算法内容整理

文章目录 P、NP、NP-hard 和 NPC多项式时间概念区分NP-hard 的证明例题 1 证明 T S P TSP TSP 问题是 N P − h a r d NP-hard NP−hard 问题 。例题 2 证明最大加权独立集问题是 N P − h a r d NP-hard NP−hard 问题。 扩展 NP-hard 问题3-SAT 问题TSP 旅行商问题 Load B…

c#网络Tcp和udp

TCP 通信 TCP 服务端 Socket tcpServer new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ipAddress new IPAddress(new byte[] { 192, 168, 1, 5 }); IPEndPoint ipEndPoint new IPEndPoint(ipAddress, 7788); tcpServer.Bind(ip…

AI大模型的制造业场景,一文读懂

导读 如何认识这一轮AI技术发展影响的深度和广度&#xff1f;如何判断这一轮AI技术变革的性质&#xff1f; AI大模型是通用人工智能发展的重要里程碑。中央会议关于人工智能发展提出三个第一次&#xff1a;第一次提出“通用人工智能”&#xff0c;第一次提出“产业智能化”&a…

武汉星起航:激发中国卖家潜力,亚马逊减免政策共筑电商辉煌

在全球化电子商务的浪潮中&#xff0c;亚马逊作为全球领先的电商平台&#xff0c;一直致力于为卖家提供卓越的服务和支持。特别是对于中国卖家而言&#xff0c;亚马逊的减免优惠政策无疑是一股强大的助力&#xff0c;帮助他们在不断发展的市场中脱颖而出&#xff0c;实现业务的…

设计模式 - Observer Pattern 观察者模式

文章目录 定义观察者模式的实现构成构成UML图 观察者模式的代码实现场景代码实现 总结优点缺点应用场景 其他设计模式文章&#xff1a; 定义 观察者模式是行为型模式的一种&#xff0c;它定义对象间的一种一对多的依赖关系&#xff0c;使得每当一个对象改变状态&#xff0c;它…

重温react-08(createContext使用方式)

react中的createContext使用方式 简介一下&#xff0c;就是组件之间可以互相通信的比较好用的传值方式&#xff0c;话不多说直接上代码。 以下介绍的是类组件中的方式&#xff0c;在函数组件中不是如此使用的。 定义一个通用的方法 import { createContext } from "react…

MathType7.6专业数学公式编辑器!与Word、PPT等常用软件无缝对接。

MathType&#xff0c;一款专业的数学公式编辑器&#xff0c;以其强大的功能和友好的用户界面&#xff0c;在科研、教学等领域广受欢迎。它支持丰富的数学符号和公式模板&#xff0c;满足不同用户的需求。同时&#xff0c;MathType还提供了多种输出格式&#xff0c;方便与其他文…

基于YOLOv9+pyside的安检仪x光危险物物品检测(有ui)

安全检查在公共场所确保人身安全的关键环节&#xff0c;不可或缺。X光安检机作为必要工具&#xff0c;在此过程中发挥着重要作用。然而&#xff0c;其依赖人工监控和判断成像的特性限制了其应用效能。本文以此为出发点&#xff0c;探索了基于Torch框架的YOLO算法在安检X光图像中…

在linux 下交叉编译gdb 8.1.1 ,生成 windows下的exe程序

在Linux环境下进行交叉编译,生成适用于Windows的可执行程序(.exe),需要使用交叉编译工具链。对于特定的GDB版本(如8.1.1),你需要确保有适用于目标平台(Windows)的交叉编译工具链。以下是一些基本步骤和考虑因素: 获取GDB源码:首先,需要下载GDB 8.1.1的源码包。你可…

《数据结构与算法基础 by王卓老师》学习笔记——类C语言有关操作补充

1.元素类型说明 2.数组定义 3.C语言的内存动态分配 4..C中的参数传递 5.传值方式 6.传地址方式 例子

【计算机网络】期末复习(2)

目录 第一章&#xff1a;概述 第二章&#xff1a;物理层 第三章&#xff1a;数据链路层 第四章&#xff1a;网络层 第五章&#xff1a;传输层 第一章&#xff1a;概述 三大类网络 &#xff08;1&#xff09;电信网络 &#xff08;2&#xff09;有线电视网络 &#xff0…

快速了解GPT-4o和GPT-4区别

GPT-4o简介 在5月14日的OpenAI举行春季发布会上&#xff0c;OpenAI在活动中发布了新旗舰模型“GPT-4o”&#xff01;据OpenAI首席技术官穆里穆拉蒂&#xff08;Muri Murati&#xff09;介绍&#xff0c;GPT-4o在继承GPT-4强大智能的同时&#xff0c;进一步提升了文本、图像及语…

px、em、rem、rpx 作用和用法详解

px px像素&#xff08;Pixel&#xff09;。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。 PX特点 IE无法调整那些使用px作为单位的字体大小&#xff1b; 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位&#xff1b; Firefox能够调整px和em&#xff…

JVM原理(四):JVM垃圾收集算法与分代收集理论

从如何判定消亡的角度出发&#xff0c;垃圾收集算法可以划分为“引用计数式垃圾收集”和“追踪式垃圾收集”两大类。 本文主要介绍的是追踪式垃圾收集。 1. 分代收集理论 当代垃圾收集器大多遵循“分代收集”的理论进行设计&#xff0c;它建立在两个假说之上&#xff1a; 弱分…

C++11中如何创建线程

在C11中&#xff0c;创建线程变得非常简单和标准化&#xff0c;因为C11引入了线程库&#xff08;<thread>&#xff09;。这个库提供了std::thread类&#xff0c;使得创建和管理线程变得更加直接和方便。 以下是如何在C11中创建线程的基本步骤&#xff1a; 包含线程库&a…

重建控制文件

----------------------------------------------------以下是单节点--------------------------------------------------- 一、现象 1、某次测试环境数据库重启&#xff0c;报如下错误 ORA-38760: This database instance failed to turn on flashback database 启动到mo…

C# 特性 Attribute 反射 Reflection 元数据 Metadata 未完

在C#中&#xff0c;元数据&#xff08;Metadata&#xff09;是指与程序代码本身相关的数据&#xff0c;这些数据提供了代码的额外信息&#xff0c;但并不直接影响代码的执行。元数据在.NET框架中扮演着重要的角色&#xff0c;以下是一些常见的元数据类型和它们的用途&#xff1…

vue插槽的简单使用

默认插槽 1.在Category中创建插槽 <slot>默认值<slot/> 2.在App中使用 <Category tittle"美食"> <ul ><li v-for"(l,index) in foods" :key"index">{{l}}</li></ul> </Category> 3.运行后的…

【IC验证】UVM实验lab05

1. 寄存器建模的要点和顺序 1.1 寄存器创建 定义单个uvm_reg&#xff0c;各个域的确定&#xff0c;并利用configure函数来配置属性&#xff1b; class ctrl_reg extends uvm_reg;uvm_object_utils(ctrl_reg)/*uvm_reg;uvm_mem;uvm_reg_map;uvm_reg_block都继承于uvm_object类…