当前位置: 首页 > news >正文

Java mybatis day1015

ok了家人们,今天学习了mybatis这个框架,我们一起去看看吧

.Mybatis简介

1.1 Mybatis概述

MyBatis 最初是 Apache 的一个开源项目 iBatis, 2010 6
这个项目由 Apache Software Foundation 迁移到了
Google Code 。随着开发团队转投 Google Code 旗下,
iBatis3.x 正式更名为 MyBatis 。代码于 2013 11 月迁移到
Github
MyBatis 是一款优秀的持久层框架,用于简化 JDBC
发。它支持自定义 SQL 、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获
取结果集的工作。 MyBatis 可以通过简单的 XML 或注解来
配置和映射原始类型、接口和 Java POJO Plain Old Java
Objects ,普通老式 Java 对象)为数据库中的记录。
官网: https://mybatis.org/mybatis-3/zh/index.html

1.2 浅谈JDBC代码

public class DemoTest {public static void main(String[] args) {//1. 注册驱动Class.forName("com.mysql.jdbc.Driver");//2. 获取Connection连接String url = "jdbc:mysql:///db1? useSSL=false";String uname = "root";String pwd = "1234";Connection conn =DriverManager.getConnection(url, uname, pwd);// 接收输入的查询条件String gender = "男";// 定义sqlString sql = "select * from tb_user where gender = ?";// 获取pstmt对象PreparedStatement pstmt =conn.prepareStatement(sql);// 设置?的值pstmt.setString(1,gender);// 执行sqlResultSet rs = pstmt.executeQuery();// 遍历Result,获取数据User user = null;ArrayList<User> users = new ArrayList<>();while (rs.next()) {//获取数据int id = rs.getInt("id");String username =rs.getString(“username”);String password =rs.getString(“password”);//创建对象,设置属性值user = new User();user.setId(id);user.setUsername(username);user.setPassword(password);user.setGender(gender);//装入集合users.add(user);}//释放资源rs.colse();pstmt.colse();conn.close();}
}

  • 硬编码
注册驱动、获取连接。连接数据库的四个基本信息,以
后如果要将 Mysql 数据库换成其他的关系型数据库的
话,这四个地方都需要修改,如果放在此处就意味着要
修改我们的源代码。
如果表结构发生变化, SQL 语句就要进行更改。这也不
方便后期的维护。
  • 操作繁琐
手动设置参数
手动封装结果集
MyBatis SQL Java 编码分开,功能边界清晰。 Java 代码专
注业务、 SQL 语句专注数据
MyBatis :免除了几乎所有的 JDBC 代码以及设置参数和获取
结果集的工作

1.3 框架名词解释

  • 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
  • 在框架的基础之上构建软件编写更加高效、规范、通用、
    可扩展

.快速入门(基于Mybatis3式)

2.1 入门案例实现步骤

  • 创建数据库和表
  • 创建模块,导入坐标
  • 实体类准备
  • 编写Mybatis核心配置文件
  • 编写Mapper接口
  • 编写 SQL 映射文件
  • 测试

创建数据库和表

CREATE TABLE t_emp(
emp_id INT primary key AUTO_INCREMENT,
emp_name CHAR(100),
emp_salary DOUBLE(10,5)
);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("张三",200.33);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("李四",200.44);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("王五",200.55);
创建模块,导入坐标
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次
不需要导入连接池,mybatis自带! -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connectorjava</artifactId>
<version>8.0.25</version>
</dependency><!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiterapi</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
实体类准备
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Double getEmpSalary() {
return empSalary;
}
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
@Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", empSalary=" + empSalary +
'}';
}
}
编写 Mybatis 核心配置文件
  • 替换连接信息 解决硬编码问题
  • 在模块下的 resources 目录下创建 mybatis 的配置文件
    mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
config.dtd">
<!--configuration表示mybatis框架的核心配置文件的根标
签,配置-->
<configuration>
<!--
environments:表示当前mybatis框架的环境:开发
测试环境等
一个environments标签下面可以书写多个
environment
一个environment标签代表一个环境
-->
<environments default="development">
<environment id="development">
<!--
事务管理,这里先使用mybatis框架的默认
管理type="JDBC",实际开发中
mybatis框架的事务由spring框架
-->
<transactionManager type="JDBC">
</transactionManager>
<!---->
<dataSource type="POOLED">
<property name="driver"
value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm_01"/><property name="username"
value="root"/>
<property name="password"
value="123456"/>
</dataSource>
</environment>
</environments>
<!--加载映射配置文件-->
<mappers>
<mapper resource="EmployeeMapper.xml">
</mapper>
</mappers>
</configuration>

编写Mapper接口

Mybatis 中的 Mapper 接口相当于以前的 Dao 。但是区别在
于, Mapper 仅仅只是建接口
package com.lzw.mapper;
import com.lzw.pojo.Employee;
import java.util.List;
//接口只规定方法,参数和返回值!映射配置文件中编写具体SQL
语句!
public interface EmployeeMapper {
public List<Employee> findAll();
}
编写 SQL 映射文件
  • 统一管理sql语句,解决硬编码问题
  • 在模块的 resources 目录下创建映射配置文件
    EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<!--namespace:名称空间 该映射配置文件和哪个Mapper接口
进行映射绑定-->
<mapper
namespace="com.lzw.mapper.EmployeeMapper">
<!--
id:唯一标识,映射接口的方法
resultType:输出的参数类型
-->
<select id="findAll"
resultType="com.lzw.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
</select>
</mapper>
测试
public class DemoTest {
//入门案例
@Test
public void test01() throws IOException {
//读取核心配置文件
InputStream in =
Resources.getResourceAsStream("mybatisconfig.xml");
//构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象获取SqlSession对象(就是connection)
SqlSession sqlSession =
sqlSessionFactory.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//处理结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
}

2.2 Lombok插件的使用(简化代码)

使用 Lombok 注解就可以省略生成 getXxx() setXxx() 方法、
toString() 方法、构造器等固定格式代码的繁琐操作,提高开
发效率。包括 Logger 日志对象。
Lombok 原理: Lombok 是将自动生成的代码织入字节码文件
中,从而实现:源代码没有,但是字节码文件有 —— 毕竟我们
最终运行的是字节码文件,只要字节码文件中有即可。而这个
过程因为要参与源文件编译,所以需要安装 IDEA 插件。
Lombok 安装
加入依赖
  <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>
注解功能介绍
注解
作用
@Data
生成 getXxx() 方法、 setXxx()
法、 toString() equals()
canEqual() hashCode() 方法
@AllArgsConstructor
生成全参构造器
@NoArgsConstructor
生成无参构造器
@Slf4j
生成日志对象
@Getter
生成 getXxx() 方法
@Setter
生成 setXxx() 方法
@ToString
生成 toString() 方法
使用 Lombok
package com.cjx.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {private Integer empId;private String empName;private Double empSalary;
}

2.3 日志框架(便于调试)

2.3.1 用日志打印替代sout
sout 有什么问题
System.out 对象是一个输出流对象,所以控制台输出信息
本质上是 I/O 操作。而 I/O 操作是项目运行过程中两大性能
瓶颈之一。
项目上线时,希望把所有(或一部分) sout 打印关闭,但
是只能手动一个一个查找,耗费开发人员的极大精力,因
sout 的无度使用会使它分散在项目的各个角落。
使用 [ 日志框架 ] 的好处
设定级别,统一管理。日志框架会按照事件的严重程度来
划分级别,例如:
        错误(Error ):表示程序运行出错,比如抛异常等情
        况。
        警告(Warning ):表示程序运行过程中有潜在风险,
        但此时并没有报错。
        信息(Info ):表示程序运行过程中完成了一个关键动
        作,需要以程序运行信息的形式告知开发者。
        调试(Debug ):表示程序运行过程中更加细致的信
        息,协助程序员调试程序。
灵活指定输出位置
        使用日志框架不一定是打印到控制台,也可以保存到文
        件中或者保存到数据库。这就看具体的项目维护需求。
自定义日志格式
        打印日志数据可以使用日志框架的默认格式,也可以根
        据需要定制。
基于日志分析问题
        将来我们开发的应用系统中,不仅包含Java 代码,还有
        很多中间件服务器。任何子系统出现故障我们都是通过
        日志来定位问题、分析故障原因。甚至更复杂的系统还
        会专门开发日志子系统,在主系统出现问题时抓取日志
        数据供维护人员参考。而日志数据必须要有确定格式才
        便于格式化和抓取,这肯定不是随意写sout 就能实现
        的。
通过在配置文件中指定某一个日志级别来控制系统要打印的内
容。日志框架会打印 当前指定级别 的日志和比当前指定级别
严重 的级别的日志。
例如在开发阶段,我们指定 debug 级别,项目上线修改成 info
级别,那么所有 debug 级别的日志就都不打印了,不需要到项
目代码中一个一个修改,非常方便。
2.3.2 Java日志体系演变

门面:类似于标准层、接口层

名称
说明
JCL Jakarta Commons Logging
陈旧
SLF4J Simple Logging Facade for Java)
适合( 同一作
jboss-logging
特殊专业领域使用

实现
名称
说明
log4j
最初版( 同一作者
JUL
java.util.logging
JDK 自带
log4j2
Apache 收购 log4j 后全面重构,
内部实现和 log4j 完全不同
logback
优雅、强大( 同一作者
最佳拍档
  • 门面:SLF4J
  • 实现:logback
2.3.3 日志用法
  • 依赖导入
<!-- 日志 会自动传递slf4j门面-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
  • 引入配置
Logback 要求配置文件名称必须是 logback.xml ,存放路径在
main/resources 目录下。
通过配置文件,可以配置输出格式、输出级别、输出位置等!
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置,ConsoleAppender表示输出
到控制台 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程
名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}]
[%-5level] [%thread] [%logger]
[%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
2.4 工具类抽取(简化代码)
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:
TRACE、DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别
的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通
过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别,可也是包名或全类
名。 -->
<logger name="com.lzw.mapper" level="DEBUG"
/>
</configuration>

2.4 工具类抽取(简化代码)

package com.cjx.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;public class SqlSessionUtil {private static SqlSessionFactory sqlSessionFactory=null;static {try {//读取核心配置文件InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//构建SqlSessionFactory工厂对象sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);} catch (IOException e) {e.printStackTrace();}}public static SqlSession openSession(){//通过SqlSessionFactory工厂对象获取SqlSession对象(就是connection)SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}
}
package com.cjx.test;import com.cjx.mapper.EmployeeMapper;
import com.cjx.pojo.Employee;
import com.cjx.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DemoTest {//查询所有@Testpublic void test01(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法List<Employee> employeeList = employeeMapper.findAll();//处理结果for (Employee employee : employeeList) {System.out.println(employee);}//释放资源sqlSession.close();}

2.5 增删改查

  • Mapper接口
package com.cjx.mapper;import com.cjx.pojo.Employee;
import org.apache.ibatis.annotations.Param;import java.util.List;
import java.util.Map;public interface EmployeeMapper {//查询所有数据List<Employee> findAll();//查询单个数据Employee findEmpById(Integer empId);//添加一条数据public Integer insertEmp(Employee employee);//修改一条数据public Integer updateEmp(Employee employee);//删除一条数据public Integer deleteEmpById(Integer empId);//修改一条数据 零散的简单类型数据public Integer updateEmpById(@Param("empName") String empName,@Param("empSalary") double empSalary,@Param("empId") Integer empId);//修改一条数据public Integer update(Map<String,Object> map);
}
  • 映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 接口的全限定名-->
<mapper namespace="com.cjx.mapper.EmployeeMapper"><!--id:唯一标识 接口的方法名保持一致--><!--结果类型:如果是集合 写集合的元素的类型--><select id="findAll"  resultType="Employee">select * from t_emp</select><select id="findEmpById" parameterType="int" resultType="Employee">select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}</select><insert id="insertEmp">insert into t_emp values(null,#{empName},#{empSalary})</insert><update id="updateEmp">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update><delete id="deleteEmpById" parameterType="int">delete from t_emp where emp_id=#{empId}</delete><update id="updateEmpById">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update><update id="update" parameterType="Map">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update>
</mapper>
  • 测试
package com.cjx.test;import com.cjx.mapper.EmployeeMapper;
import com.cjx.pojo.Employee;
import com.cjx.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DemoTest {//查询所有@Testpublic void test01(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法List<Employee> employeeList = employeeMapper.findAll();//处理结果for (Employee employee : employeeList) {System.out.println(employee);}//释放资源sqlSession.close();}//通过Id查询数据@Testpublic void test02(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee emp = employeeMapper.findEmpById(1);//处理结果System.out.println(emp);//释放资源sqlSession.close();}//新增一条数据@Testpublic void test03(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee employee = new Employee(null,"赵六",260.0);Integer emp = employeeMapper.insertEmp(employee);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test04(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee employee = new Employee(1,"zs",230.0);Integer emp = employeeMapper.updateEmp(employee);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//删除一条数据根据Id@Testpublic void test05(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.deleteEmpById(4);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test07(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.updateEmpById("ww",255.55,3);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test06(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Map<String,Object> map = new HashMap<>();map.put("empName","ls");map.put("empSalary",244.44);map.put("empId",2);Integer emp = employeeMapper.update(map);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}
}
  • 注意事项
插入操作涉及数据库数据变化,所以要使用 sqlSession 对象显
示的提交事务,即 sqlSession.commit()
增删改接口的返回值是 Integer, 表示返回影响的行数 , 在映射配
置文件中不需要设置 resultType

. MyBatis核心配置文件

MyBatis 的核心配置文件包含了会深深影响 MyBatis 行为的
设置和属性信息。 配置文档的顶层结构如下:
  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
  • databaseIdProvider(数据库厂商标识)
  • mappers(映射器)
注意事项:在配置时按照以上顺序进行配置

3.1 properties(属性)

实际开发中,习惯将数据源的配置信息单独抽取成一个
properties 文件,该标签可以加载额外配置的 properties
件。
  • db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_01
jdbc.username=root
jdbc.password=123456
  • mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--加载外部properties--><properties resource="db.properties"></properties><!--开启自动映射 驼峰命名--><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings><!--起别名--><typeAliases><package name="com.cjx.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--8.x--><property name="driver" value="${jdbc.driver}"/><!--5.x--><!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--核心配置文件加载映射配置文件--><mappers><mapper resource="EmployeeMapper.xml"/></mappers>
</configuration>

3.2 settings(设置)

设置名
描述
mapUnderscoreToCamelCase
是否开启驼峰命名自动
映射,即从经典数据库
列名 A_COLUMN 映射
到经典 Java 属性名
aColumn 。 取值: true
| false 默认值: false
<!--开启驼峰映射-->
<settings>
<setting name="mapUnderscoreToCamelCase"
value="true"/>
</settings>

3.3 typeAliases(类型别名)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML
配置,意在降低冗余的全限定类名书写。
 <typeAliases><package name="com.cjx.pojo"/></typeAliases>

3.4 environments(环境配置)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL
映射应用于多种数据库之中, 现实情况下有多种理由需要这
么做。例如,开发、测试和生产环境需要有不同的配置。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
<environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--8.x--><property name="driver" value="${jdbc.driver}"/><!--5.x--><!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments>

.数据输入

  • 简单类型:只包含一个值的数据类型
    • 基本数据类型:intbyteshortdouble……
    • 基本数据类型的包装类型:IntegerCharacterDouble……
    • 字符串类型:String
  • 复杂类型:包含多个值的数据类型
    • 实体类类型:EmployeeDepartment……
    • 集合类型:ListSetMap……
    • 数组类型:int[]String[]……
    • 复合类型:List<Employee>、实体类中包含集合……

4.1 参数占位符

#{} :执行 SQL 时,会将 #{} 占位符替换为?,将来自动设
置参数值。从案例可以看出使用 #{} 底层使用的是
PreparedStatement
public interface EmployeeMapper {
//查询单个数据
public Employee findEmpById01(Integer
empId);
}
<select id="findEmpById01" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = #{empId}
</select>

${} :拼接 SQL 。底层使用的是 Statement ,会存在 SQL 注入问题
public interface EmployeeMapper {
//查询单个数据
public Employee findEmpById02(Integer
empId);
}
<select id="findEmpById02" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = ${empId}
</select>

结论:实际开发中,能用 #{} 实现的,肯定不用 ${}

4.2 parameterType使用

对于有参数的 mapper 接口方法,我们在映射配置文件中应该
配置 ParameterType 来指定参数类型。只不过该属性都可以
省略。
<insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert>

4.3 单个简单类型参数

4.3.1 编写接口方法
public interface EmployeeMapper {
//删除一条数据
public Integer deleteEmpById(Integer empId);
}
4.3.2 编写SQL语句
<delete id="deleteEmpById"
parameterType="java.lang.Integer">
delete from t_emp where emp_id = #{empId}
</delete>
  • 增删改接口的返回值是 Integer, 表示返回影响的行数 , 在映
    射配置文件中不需要设置 resultType
  • 单个简单类型参数,在 #{} 中可以随意命名,但是没有必
    要。通常还是使用和接口方法参数同名。
4.3.3 编写测试方法
 //删除一条数据根据Id@Testpublic void test05(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.deleteEmpById(4);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}

4.4 实体类类型参数

将多个参数封装成一个 实体对象 ,将该实体对象作为接口的
方法参数。该方式要求在映射配置文件的 SQL 中使用 #{ 内容 }
时,里面的内容必须和实体类属性名保持一致。
4.4.1 编写接口方法
public interface EmployeeMapper {
//添加一条数据
public Integer insertEmp(Employee employee);
}
4.4.2 编写SQL语句
<!--实体传参,在映射配置文件中取值,直接写对象的属性名-->
<insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert>
4.4.3 编写测试方法
@Test
public void testInsert(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"王五",555.22);
Integer row = employeeMapper.insertEmp(employee);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

4.5 零散的简单类型数据

零散的多个简单类型参数,如果没有特殊处理,那么 Mybatis
无法识别自定义名称:
4.5.1 编写接口方法
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer updateNameById(String
empName,Integer empId);
}
4.5.2 编写SQL语句
<update id="updateNameById">
update t_emp set emp_name = #{empName} where
emp_id = #{empId}
</update>
4.5.3 编写测试方法
@Test
public void testupdateNameById(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer row =
employeeMapper.updateNameById("zs",1);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

4.5.4 解决方案
  • 修改配置文件取值方式
<update id="updateNameById">
update t_emp set emp_name = #{param1} where
emp_id = #{param2}
</update>
  • 使用 @Param(" 参数名称 ") 标记每一个参数,在映射配置
    文件中就需要使用 #{ 参数名称 } 进行占位
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer
updateNameById(@Param("empName") String empName,
@Param("empId") Integer empId);
}
<update id="updateNameById">
update t_emp set emp_name = #{empName} where
emp_id = #{empId}
</update>

4.6 Map类型参数

将多个参数封装到 map 集合中,将 map 集合作为接口的方法
参数。该方式要求在映射配置文件的 SQL 中使用 #{ 内容 } 时,
里面的内容必须和 map 集合中键的名称一致。
4.6.1 编写接口方法
public interface EmployeeMapper {
//修改一条数据
public Integer updateEmp(Map<String,Object>
map);
}
4.6.2 编写SQL语句
<!--通过key获取value的值-->
<update id="updateEmp" parameterType="Employee">
update t_emp set emp_name = #
{empName},emp_salary = #{empSalary} where
emp_id = #{empId}
</update>
4.6.3 编写测试代码
@Test
public void testUpdate(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String,Object> map=new HashMap<>();
map.put("empId",3);
map.put("empName","ww");
map.put("empSalary",55.33);
Integer row = employeeMapper.updateEmp(map);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

.数据输出

5.1 输出概述

数据输出总体上有两种形式:
  • 增删改操作返回受影响行数:直接在接口方法中使用 int
    long 类型接收即可
  • 查询操作的查询结果
我们需要做的是,指定查询的输出数据类型即可!
并且插入场景下,实现主键数据回显示!
resultType = " 全限定符 | 别名 | 如果是返回集合类型,写
范型类型即可

5.2 返回单个简单类型

5.2.1 编写接口方法
public interface EmployeeMapper {
//查询总条数
public Integer findTotalCount();
}
5.2.2 编写SQL语句
<select id="findTotalCount" resultType="int">
select count(*) from t_emp
</select>
 5.2.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer totalCount =
employeeMapper.findTotalCount();
//输出结果
System.out.println(totalCount);
//释放资源
sqlSession.close();
}

5.3 返回实体类对象

5.3.1 编写接口方法
public interface EmployeeMapper {
//根据ID查询用户信息
public Employee findEmpById(Integer empId);
}
5.3.2 编写SQL语句
<select id="findEmpById" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = #{empId}
</select>
5.3.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee =
employeeMapper.findEmpById(1);
//输出结果
System.out.println(employee);
//释放资源
sqlSession.close();
}

5.4 返回List类型

查询结果返回多个实体类对象,希望把多个实体类对象放在
List 集合中返回。此时不需要任何特殊处理,在 resultType
性中还是设置实体类类型即可。
5.4.1 编写接口方法
public interface EmployeeMapper {
//查询所有数据
public List<Employee> findAll();
}
5.4.2 编写 SQL 语句
<select id="findAll" resultType="Employee">
select * from t_emp
</select>
5.4.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//输出结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}

5.5 返回Map类型

适用于 SQL 查询返回的各个字段综合起来并不和任何一个现有
的实体类对应,没法封装到实体类对象中。
5.5.1 编写接口方法
public interface EmployeeMapper {
//查询所有员工的最高工资,最低工资,平均工资
public Map<String,Object> findSalary();
}
5.5.2 编写SQL语句
<select id="findSalary" resultType="Map">
select max(emp_salary) 最高工资,min(emp_salary) 最低工资,avg(emp_salary) 平局工资 from t_emp
</select>
5.5.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String, Object> map =
employeeMapper.findSalary();
//输出结果
Set<Map.Entry<String, Object>> entrySet =
map.entrySet();
for (Map.Entry<String, Object> entry :
entrySet) {
System.out.println(entry.getKey()+"..."+entry.g
etValue());
}
//释放资源
sqlSession.close();
}

5.6 主键回填

5.6.1 自增长类型主键

public interface EmployeeMapper {
//添加数据
public Integer insertEmp(Employee employee);
}
<!--
主键回填:当Mybatis执行新增后,会将数据库中该
条数据新增后的主键回填到实体的属性上
useGeneratedKeys:是否启用主键回填
keyProperty:指定主键回填到实体的哪个属性上
keyColumn:指定数据库中哪一列是主键(可选)
-->
<insert id="insertEmp" parameterType="Employee"
useGeneratedKeys="true" keyProperty="empId">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert>
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"赵
六",11.22);
Integer integer =
employeeMapper.insertEmp(employee);
//输出结果
System.out.println(integer);
//后续需要完善员工信息
System.out.println(employee);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
5.6.2 非自增长类型主键
而对于不支持自增型主键的数据库或者字符串类型主键,则可
以使用 selectKey 子元素: selectKey 元素将会首先运行, id
会被设置,然后插入语句会被调用!
使用 selectKey 帮助插入 UUID 作为字符串类型主键示例:
CREATE TABLE t_user (
id varchar(64) primary key,
username varchar(50),
password varchar(50)
)
public interface UserMapper {
//添加数据
public Integer insertUser(User user);
}
<mapper namespace="com.lzw.mapper.UserMapper">
<insert id="insertUser"
parameterType="user">
<!--
keyProperty:设置为实体的哪个属性,
resultType:设置返回值类型,
order:值为after和before
after: sql之后执行,before: sql之前执行
-->
<selectKey order="BEFORE"
resultType="string" keyProperty="id">
select replace(UUID(),'-','')
</selectKey>
insert into t_user values(#{id},#
{username},#{password})
</insert>
</mapper>
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
UserMapper userMapper =
sqlSession.getMapper(UserMapper.class);
//通过多态调用方法
//String id=
UUID.randomUUID().toString().replace("-","");
User user=new User(null,"zs","123456");
Integer integer =
userMapper.insertUser(user);
//输出结果
System.out.println(integer);
//后续需要完善用户信息
System.out.println(user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

see you later!!!

相关文章:

Java mybatis day1015

ok了家人们&#xff0c;今天学习了mybatis这个框架&#xff0c;我们一起去看看吧 一.Mybatis简介 1.1 Mybatis概述 MyBatis 最初是 Apache 的一个开源项目 iBatis, 2010 年 6 月 这个项目由 Apache Software Foundation 迁移到了 Google Code 。随着开发团队转投 Google Cod…...

音乐播放器项目专栏介绍​

1.简介 本专栏使用Qt QWidget作为显示界面&#xff0c;你将会学习到以下内容&#xff1a; 1.大量ui美化的实例。 2.各种复杂ui布局。 3.常见显示效果实现。 4.大量QSS实例。 5.Qt音频播放&#xff0c;音乐歌词文件加载&#xff0c;展示。 6.播放器界面换肤。 相信学习了本专栏…...

如何修改SpringBoot内置容器默认上下文

引言 默认情况下&#xff0c;Spring boot 应用程序通过上下文路径“/”访问&#xff0c;这是嵌入式服务器的默认设置&#xff0c;即我们可以直接通过http://localhost:8080/访问该应用程序。 但是在生产环境中部署 Spring Boot 应用程序时&#xff0c;指定上下文路径是一个常…...

R语言详解predict函数

R语言中predict函数在建立模型&#xff0c;研究关系时常用。但是不同type得到的结果常常被混为一谈&#xff0c;接下来&#xff0c;探讨predict得到的不同结果。 #数据 set.seed(123) n<-1000 age<-rnorm(n,mean50,sd10) gender<-rbinom(n,1,0.5) disease<-rbinom…...

QT 实现随机码验证

1.界面实现效果 以下是具体的项目需要用到的效果展示&#xff0c;用于验证字母。 2.简介 自定义CaptchaMovableLabel&#xff0c;继承自QLabel类&#xff1a; 中间的4个字母&#xff0c;就是CaptchaMovableLabel类来实例化的对象。 主要功能如下&#xff1a; 1.显示字母&am…...

集合框架12:Set集合概述、Set接口使用

视频链接&#xff1a;13.24 Set接口使用_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1zD4y1Q7Fw?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p24 1、Set集合概述 特点&#xff1a;无序、无下标&#xff0c;元素不可…...

如何打开荣耀手机的调试模式?

问题描述&#xff1a; 最近用荣耀手机进行测试&#xff0c;打开开发者选项&#xff0c;打开USB调试&#xff0c;在选择USB配置时&#xff0c;发现仅有选择USB以太网才可以连接Android Studio&#xff0c;也就是打开ADB调试模式。 但是&#xff0c;打开USB以太网后&#xff0c…...

Meta新模型Dualformer:融合快慢思维,推理能力媲美人脑

Meta 的 FAIR 团队最近推出了一款名为 Dualformer 的全新 Transformer 模型&#xff0c;该模型模仿人类的双重认知系统&#xff0c;能够无缝整合快速和慢速推理模式&#xff0c;在推理能力和计算效率上取得了显著突破。 人类的思维过程通常被认为是由两种系统控制的:系统1快速…...

CDGA|数据治理:如何让传统行业实现数据智能

在当今这个数字化时代&#xff0c;数据已成为推动各行各业转型升级的关键力量。对于传统行业而言&#xff0c;如何从海量、复杂的数据中挖掘价值&#xff0c;实现“数据智能”&#xff0c;成为了提升竞争力、优化运营效率、创新业务模式的重要途径。本文将探讨数据治理如何助力…...

Spring源码5.2.9 编译踩坑

源码编译踩坑 拉取源码 我这块以5.2.9版本为例 spring-projects/spring-framework at v5.2.9.RELEASE (github.com) 版本分析 确定版本 这块将Gradle升级到了5.6.4 &#xff0c;我们去官网下载即可 Gradle安装 Gradle | Releases 解压 将其解压到你想存放的文件夹 配置环…...

【前端】如何制作一个自己的网页(5)

上节课我们学习了以下知识&#xff1a; 1、网页中常见的文本元素&#xff0c;如标题元素与段落元素&#xff1b; 2、两个通用属性id与class&#xff1b; 3、元素的两种类型——块级元素与行内元素。 其实除了文本内容外&#xff0c;网页还可以包含图片、超链接等各类信息&a…...

Unity实战案例全解析 类宝可梦回合制的初级案例 源码分析(加了注释和流程图)

这是一个老教程了&#xff0c;但是对于没有写过回合制的初级程序同学来讲是比较适合的&#xff0c;也可以直接看源码&#xff0c;半小时内可以解决战斗 当然&#xff0c;我也没写过回合制系统所以就到处找&#xff0c;思路明白了就能自己修改了 视频教程 - 油管链接 Turn-Bas…...

AI绘图大模型 Stable Diffusion 使用详解

近年来&#xff0c;生成式 AI 技术&#xff0c;特别是 AI 绘图模型的进展令人瞩目。Stable Diffusion 是其中一款开源的大规模图像生成模型&#xff0c;它能够根据文本描述生成高质量的图像&#xff0c;支持从写实风格到卡通、幻想等各种不同的视觉效果。本文将深入介绍如何使用…...

es索引库操作和使用RestHignLevelClient客户端操作es

目录 es索引库操作 mapping映射操作 索引库的CURD操作 1.创建索引库和映射 ​编辑 2.查询索引库 3.删除索引库 4.修改索引库 5.总结 文档的CURD操作 1.新增文档 2.查询文档 3.删除文档 4.修改文档 全量修改 增量修改 5.总结 RestAPI 使用API例子 需要的数…...

安卓数据共享

在 Android 中&#xff0c;数据共享是指不同应用之间共享数据或同一应用不同组件之间共享数据的机制。SQLite 数据库、内容提供者&#xff08;Content Provider&#xff09;、共享偏好&#xff08;Shared Preferences&#xff09;和文件存储等方式可以实现数据共享。下面将详细…...

Gin框架操作指南02:JSON渲染

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;本教程采用工作区机制&#xff0c;所以一个项目下载了Gin框架&#xff0c;其余项目就无需重复下载&#xff0c;想了解的读者可阅读第一节&#xff1a;Gin操作指南&#…...

【随手记】MySQL单表访问方法

在MySQL查询优化器中&#xff0c;单表访问方法&#xff08;Access Method&#xff09;指的是查询时数据库如何从一个表中访问所需的数据。不同的访问方法适用于不同的查询场景&#xff0c;主要包括 const、ref、ref_or_null、range、index 和 all。这些方法从效率上依次递减&am…...

机器学习:情感分析的原理、应用场景及优缺点介绍

一、情感分析算法概述 情感分析是自然语言处理中的一个重要任务&#xff0c;主要用于判断文本中所包含的情感倾向&#xff0c;如正面、负面或中性。 二、基于词典的情感分析算法 原理 词典构建&#xff1a;首先需要构建一个情感词典。这个词典包含了一系列带有情感倾向的词汇…...

基于SSM的医院药品管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

特征融合篇 | YOLOv10 引入动态上采样模块 | 超过了其他上采样器

本改进已集成到YOLOv8-Magic 框架 论文名称:《Learning to Upsample by Learning to Sample》 论文地址:https://arxiv.org/abs/2308.15085 代码地址:https://github.com/tiny-smart/dysample 我们提出了 DySample,一种超轻量级且有效的动态上采样器。尽管最近基于内核的…...

【Linux系列】写入文本到文件

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

【踩坑随笔】Tensorflow-GPU训练踩坑

一个无语的坑&#xff0c;4060单卡训练&#xff0c;8G内存本来就不够&#xff0c;还没开始训练就已经爆内存了&#xff0c;但是居然正常跑完了训练&#xff0c;然后一推理发现结果就是一坨。。。往回翻日志才发现原来中间有异常。 首先解决第一个问题&#xff1a;Could not lo…...

【云岚到家】-day07-4-实战项目-优惠券活动-项目准备

【云岚到家-即刻体检】-day07-4-实战项目-优惠券活动-活动管理 1 模块需求分析1.1 业务流程1.2 界面原型1.3 业务模块 2 模块设计2.1 数据流2.2 表结构设计2.2.1 优惠券活动表设计2.2.2 优惠券表设计2.2.3 优惠券核销表2.2.4 优惠券退回表 2.3 创建数据库2.4 创建工程 1 模块需…...

axios的使用

在 Vue 项目中&#xff0c;封装 Axios 并实现加密、重复请求优化、请求取消、页面切换时取消未完成的请求、以及区分上传和下载操作是非常常见的需求。下面将逐一讲解这些需求的实现方式。 1. Axios 的基本封装 首先&#xff0c;我们可以将 Axios 封装到一个服务层中&#xf…...

Ubuntu 使用命令克隆和恢复SD卡

因为平常我需要做很多张开发板的出货卡&#xff0c;测试卡&#xff0c;那么我需要将备份下来文件&#xff0c;方便后续管理&#xff0c;这里时候需要用到Ubuntu上面的命令来克隆镜像和恢复镜像到SD卡上 先查询自己的SD卡是在sdx&#xff0c;以我的为例子&#xff0c;为sdb 备…...

Java 小游戏《超级马里奥》

文章目录 一、效果展示二、代码编写1. 素材准备2. 创建窗口类3. 创建常量类4. 创建动作类5. 创建关卡类6. 创建障碍物类7. 创建马里奥类8. 编写程序入口 一、效果展示 二、代码编写 1. 素材准备 首先创建一个基本的 java 项目&#xff0c;并将本游戏需要用到的图片素材 image…...

go语言defer详解

什么是defer&#xff1f;为什么需要defer&#xff1f;怎样合理使用defer?defer进阶 defer的底层原理是什么&#xff1f;利用defer原理defer命令的拆解defer语句的参数闭包是什么&#xff1f;defer配合recover后记参考资料 什么是defer&#xff1f; defer是Go语言提供的一种用…...

【C语言】循环中断break

在循环使用过程中&#xff0c;可能遇到某些情况需要终止循环。比如按座位查找一位学生&#xff0c;循环查找&#xff0c;找到时可以直接停止。后续的循环将不再执行。 break;只跳出一层循环 例子中的素数判断&#xff0c;查找到根号n停止&#xff1a;一个合数等于两个数的乘积…...

centos ping能通但是wget超时-解决

问题截图&#xff1a; 域名解析地址为IPV6地址&#xff0c;建议您调整IPV4优先级之后&#xff0c;再尝试访问&#xff0c;请参考Linux系统IPv4/IPv6双栈接入优先使用IPv4设置&#xff1a;移动云帮助中心 实操截图&#xff1a;...

SDIO - DWC MSHC 电压切换和频率切换

背景 我们的sdio访问sd card过去一直跑在低频上&#xff0c;HS50M。前段时间给eMMc添加了HS200模式&#xff0c;eMMc的总线模式定义是这样的&#xff1a; 可以看到1.8V的IO 电压可以支持所有模式&#xff0c;我们过去的芯片&#xff0c;由硬件部门放到evb上&#xff0c;其IO …...