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

【Mybatis】Mybatis基础

文章目录

  • 前言
  • 一、搭建MyBatis
    • 1.1 创建maven工程
    • 1.2 加入log4j日志功能
    • 1.3 MyBatis的增删改查
    • 1.4 核心配置文件详解
  • 二、MyBatis获取参数值的两种方式
    • 2.1 单个字面量类型的参数
    • 2.2 多个字面量类型的参数
    • 2.3 map集合类型的参数
    • 2.4 实体类类型的参数
    • 2.5 使用@Param标识参数
  • 三、 MyBatis的各种查询功能
    • 3.1 查询一个实体类对象
    • 3.2 查询一个list集合
    • 3.3 查询一条数据为map集合
    • 3.4 查询多条数据为map集合
  • 四、 特殊SQL的执行
    • 4.1 模糊查询
    • 4.2 批量删除
    • 4.3 动态设置表名
    • 4.4 添加功能获取自增的主键
  • 五、 自定义映射resultMap
    • 5.1 resultMap处理字段和属性的映射关系
    • 5.2 多对一映射处理
      • 5.2.1 级联方式处理映射关系
      • 5.2.2 使用association处理映射关系(处理实体类类型的属性映射)
      • 5.2.3 分步查询
        • 分布查询优点
    • 5.3 一对多映射处理
      • 5.3.1 collection
      • 5.3.2 分步查询
  • 六、 动态SQL
    • 6.1 if
    • 6.2 where
    • 6.3 trim
    • 6.4 choose、when、otherwise
    • 6.5 foreach
    • 6.6 SQL片段
  • 七、 MyBatis的缓存
    • 7.1 MyBatis的一级缓存
    • 7.2 MyBatis的二级缓存
    • 7.3 二级缓存的相关配置
    • 7.4 MyBatis缓存查询的顺序
    • 7.5 整合第三方缓存EHCache
      • 7.5.1、添加依赖
      • 7.5.2 创建EHCache的配置文件ehcache.xml
      • 7.5.3 设置二级缓存的类型
      • 7.5.4 加入logback日志
  • 八、 Mybatis逆向工程
    • 8.1 创建逆向工程的步骤
  • 九、 分页查询
    • 分页插件的使用步骤
    • 分页插件的使用


前言

  1. MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
  2. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  3. MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录
  4. MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架

提示:以下是本篇文章正文内容,下面案例可供参考

一、搭建MyBatis

MySQL不同版本的注意事项
1、驱动类driver-class-name
MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver
MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver
2、连接地址url
MySQL 5版本的url:
jdbc:mysql://localhost:3306/ssm
MySQL 8版本的url:
jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more

1.1 创建maven工程

  1. 引入依赖
<dependencies><!-- Mybatis核心 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency></dependencies>
  1. 创建MyBatis的核心配置文件

习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring
之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。
核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
核心配置文件存放的位置是src/main/resources目录下

 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--设置连接数据库的环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm? serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!--引入映射文件--><mappers><package name="mappers/UserMapper.xml"/></mappers></configuration>
  1. 创建类
public class User {private Integer id;private String username;private String password;//有参构造public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public Integer id() {return id;}public void setId(Integer id) {this.id = id;}public String username() {return username;}public void setUsername(String username) {this.username = username;}public String password() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}
  1. 创建mapper接口

MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。

public interface UserMapper {/*** 添加用户信息
*/int insertUser();
}
  1. 创建MyBatis的映射文件
    相关概念:ORM(Object Relationship Mapping)对象关系映射。
    对象:Java的实体类对象
    关系:关系型数据库
    映射:二者之间的对应关系
Java概念数据库概念
属性表的字段/列
对象表中的一行数据

1、映射文件的命名规则:
表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下

2、 MyBatis中可以面向接口操作数据,要保证两个一致:
a> mapper接口的全类名和映射文件的命名空间(namespace)保持一致
b> mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.mybatis.mapper.UserMapper"><!--对应映射接口:int insertUser();--><insert id="insertUser">insert into t_user values(null,'admin','123456')</insert></mapper>

6 . 通过junit测试功能

//读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = newSqlSessionFactoryBuilder();//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务 
//SqlSession sqlSession = sqlSessionFactory.openSession();//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);//通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配 
映射文件中的SQL标签,并执行标签中的SQL语句
int result = userMapper.insertUser();//sqlSession.commit();System.out.println("结果:"+result)
  • SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
  • SqlSessionFactory:是“生产”SqlSession的“工厂”。
  • 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

1.2 加入log4j日志功能

  1. 加入maven依赖
<!-- log4j日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
  1. 加入log4j的配置文件

log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"><appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"><param name="Encoding" value="UTF-8" /><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" /></layout></appender><logger name="java.sql"><level value="debug" /></logger><logger name="org.apache.ibatis"><level value="info" /></logger><root><level value="debug" /><appender-ref ref="STDOUT" /></root>
</log4j:configuration>

日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细

1.3 MyBatis的增删改查

对一个表的操作放在一个xml中,UserMapper.xml

  1. 新增
<!--int insertUser();--> 
<insert id="insertUser"> insert into t_user values(null,'admin','123456') 
</insert>
  1. 删除
<!--int deleteUser();--> 
<delete id="deleteUser"> delete from t_user where id = 7 
</delete>
  1. 修改
<!--int updateUser();--> 
<update id="updateUser"> update t_user set username='ybc',password='123' where id = 6 
</update>
  1. 查询(比较特殊)

注意:
1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系
resultType:自动映射,用于属性名和表中字段名一致的情况
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
这两个属性的值都是类的全类名com.xxx.xxx

查询一个实体类对象

<!--User getUserById();--> 
<select id="getUserById" resultType="com.atguigu.mybatis.bean.User"> select * from t_user where id = 2 
</select>

查询多个,返回一个对象集合

<!--对应的映射文件的接口:List<User> getUserList();--> 
<select id="getUserList" resultType="com.atguigu.mybatis.bean.User"> select * from t_user 
</select>

1.4 核心配置文件详解

核心配置文件中的标签必须按照固定的顺序:
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?

 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--MyBatis核心配置文件中,标签的顺序:properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?--><!--引入properties文件,此后就可以在当前文件中使用${key}的方式访问value,比如下文的dataSource标签中--><properties resource="jdbc.properties" /><!--设置类型别名,在myBatis的范围中,就可以使用别名表示一个具体的类型--><typeAliases><!--typeAlias:设置某个类型的别名属性:type:设置需要设置别名的类型alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写--><!--<typeAlias type="com.atguigu.mybatis.pojo.User" alias="abc"></typeAlias>--><!--全范围内可以用User代替com.atguigu.mybatis.pojo.User--><!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>--><!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写,当类多时可以用这个方式--><package name="com.atguigu.mybatis.pojo"/></typeAliases><!--environments:配置多个连接数据库的环境属性:default:设置默认使用的环境的id--><environments default="development"><environment id="development"><!--transactionManager:设置事务管理方式属性: type="JDBC|MANAGED"1. JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理2. MANAGED:被管理,例如Spring--><transactionManager type="JDBC"/><!--dataSource:配置数据源属性:type:设置数据源的类型type="POOLED|UNPOOLED|JNDI"POOLED:表示使用数据库连接池缓存数据库连接UNPOOLED:表示不使用数据库连接池JNDI:表示使用上下文中的数据源--><dataSource type="POOLED"><!--设置连接数据库的驱动--><property name="driver" value="${jdbc.driver}"/><!--设置连接数据库的连接地址--><property name="url" value="${jdbc.url}"/><!--设置连接数据库的用户名--><property name="username" value="${jdbc.username}"/><!--设置连接数据库的密码--><property name="password" value="${jdbc.password}"/></dataSource></environment><environment id="test"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssmserverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!--引入映射文件--><mappers><!--<mapper resource="mappers/UserMapper.xml"/>--><!--以包为单位引入映射文件要求:1、mapper接口所在的包要和映射文件所在的包一致,即resources下映射文件所在目录必须和mapper接口所在目录保持一致性2、mapper接口要和映射文件的名字一致--><package name="com.atguigu.mybatis.mapper"/></mappers></configuration>

二、MyBatis获取参数值的两种方式

MyBatis获取参数值的两种方式:${}和#{}

${}的本质就是字符串拼接,#{}的本质就是占位符赋值

使用$的方式进行传参,相当于直接把参数拼接到原始的SQL里面,MyBatis不会对它进行特殊处理。若为字符串类型或日期类型的字段进行赋值时,需要手动加单引

#号占位符,等同于jdbc里面的号占位符,它相当于向PreparedStatement中的预处理语句中设置参数,而PreparedStatement中的sql语句是预编译的,SQL语句中使用了占位符规定了SQL语句的机构,并且在设置参数的时候,如果有特殊字符,会自动进行转义,所以使用#号占位符还可以防止SQL注入

<!-- User getUserByUsername(String username); -->
<select id="getUserByUsername" resultType="User"><!-- 通过${}占位符 获取参数需要加单引号-->select * from user where username = '${username}';<!-- 通过#{}占位符 获取参数填充,这里#{xxx}的xxx可以是任意名称,因为底层这就是一个占位符 -->select * from user where username = #{username};
</select>

$和#最大的区别在于,前者是动态参数,后者是占位符,动态参数无法防止SQL注入的问题,所以在实际应用中,应该尽可能的使用#号占位符
另外,$占位符,可以应用在一些动态SQL场景中,比如动态传递表名,批量删除等

2.1 单个字面量类型的参数

若mapper接口中的方法参数为单个的字面量类型
此时可以使用${}和#{}以任意的名称获取参数的值,注意${}需要手动加单引号

2.2 多个字面量类型的参数

若mapper接口中的方法参数为多个时此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;以param1,param2…为键,以参数为值;(则会两种都可以,只不过一个从0开始,一个从1开始)
因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意对于字符串或日期类型,${}需要手动加单引号

在这里插入图片描述

2.3 map集合类型的参数

若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中
只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号
在这里插入图片描述

2.4 实体类类型的参数

若mapper接口中的方法参数为实体类对象时 此时可以使用${}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号

注意,属性名和成员变量没有关系,只和get和set方法有关

在这里插入图片描述在这里插入图片描述

2.5 使用@Param标识参数

可以通过@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,
1.以@Param注解的value属性值为键,以参数为值
2.以param1,param2…为键,以参数为值;
只需要通过${}和#{}访问map集合的键就可以获取相对应的值,
注意${}需要手动加单引号

mapper接口内容
在这里插入图片描述
映射文件内容,此时${}中的内容与@param注解中的属性值一 一对应
在这里插入图片描述
测试内容
在这里插入图片描述

三、 MyBatis的各种查询功能

3.1 查询一个实体类对象

/*** 根据用户id查询用户信息
* @param id* @return 
*/User getUserById(@Param("id") int id);
<!--User getUserById(@Param("id") int id);-->
<select id="getUserById" resultType="User">select * from t_user where id = #{id}
</select>

3.2 查询一个list集合

/*** 查询所有用户信息,因为是所有,所以不用加参数
* @return*/List<User> getUserList();
<!--List<User> getUserList();-->
<select id="getUserList" resultType="User">select * from t_user
</select>

3.3 查询一条数据为map集合

/*** 根据用户id查询用户信息为map集合
* @param id* @return 
*/Map<String, Object> getUserToMap(@Param("id") int id);
<!--Map<String, Object> getUserToMap(@Param("id") int id);-->
<!--结果: {password=123456, sex=男 , id=1, age=23, username=admin}-->
<select id="getUserToMap" resultType="map">select * from t_user where id = #{id}
</select>

3.4 查询多条数据为map集合

①方式一 (将查询到的map添加到外层list中)

/**                                                                            
* 查询所有用户信息为map集合                                                         
* @return                                                                     
* 将表中的数据以map集合的方式查询,一条数据对应一个map;
* 若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取
*/List<Map<String, Object>> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">select * from t_user
</select>

②方式二 (将查询到的map添加到外层map中)

/**                                                                            
* 查询所有用户信息为map集合                                                         
* @return                                                                     
* 将表中的数据以map的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map,并
且最终要以一个map集合的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map
*/
// 以查询出来的id值为外层map的键,每条内层map为值@MapKey("id")Map<String, Object> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();--><!-- 
{ 1={password=123456, sex=男, id=1, age=23, username=admin}, 2={password=123456, sex=男, id=2, age=23, username=张三}, 3={password=123456, sex=男, id=3, age=23, username=张三} 
}--><select id="getAllUserToMap" resultType="map">select * from t_user</select>																																																																																																																																																

四、 特殊SQL的执行

4.1 模糊查询

/*** 测试模糊查询
* @param mohu* @return 
*/
List<User> testMohu(@Param("mohu") String mohu);
 <!--List<User> testMohu(@Param("mohu") String mohu);--><select id="testMohu" resultType="User"><!--select * from t_user where username like '%${mohu}%'--><!--select * from t_user where username like concat('%',#{mohu},'%')-->select * from t_user where username like "%"#{mohu}"%"</select>

4.2 批量删除

/*** 批量删除
* @param ids* @return 
*/int deleteMore(@Param("ids") String ids);
 <!--int deleteMore(@Param("ids") String ids);,ids的格式是x,x,x(用逗号隔开)--><delete id="deleteMore"><!--不能用#{ids},因为#会自动给ids加单引号,delete from t_user where id in ('x,x,x')是错误的语法-->delete from t_user where id in (${ids})</delete>

4.3 动态设置表名

/*** 动态设置表名,查询所有的用户信息
* @param tableName* @return 
*/List<User> getAllUser(@Param("tableName") String tableName);
<!--List<User> getAllUser(@Param("tableName") String tableName);--> 
<select id="getAllUser" resultType="User"><!--同样不能用#{}--> select * from ${tableName}
</select>

4.4 添加功能获取自增的主键

场景模拟:
t_clazz(clazz_id,clazz_name)
t_student(student_id,student_name,clazz_id)
1、添加班级信息
2、获取新添加的班级的id
3、为班级分配学生,即将某学的班级id修改为新添加的班级的id

 /*** 添加用户信息
* @param user* @return* useGeneratedKeys:设置使用自增的主键
* keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参 
数user对象的某个属性中
*/int insertUser(User user);
 <!--int insertUser(User user);--><!--useGeneratedKeys:设置使用自增的主键keyProperty:将添加的数据的自增主键为实体类中的参数进行赋值--><insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into t_user values(null,#{username},#{password},#{age},#{sex})</insert>

五、 自定义映射resultMap

5.1 resultMap处理字段和属性的映射关系

若字段名和实体类中的属性名不一致(比如命名不同,个数不同),则可以通过resultMap设置自定义映射

<!--resultMap:设置自定义映射属性:id:表示自定义映射的唯一标识type:查询的数据要映射的实体类的类型子标签:id:设置主键的映射关系result:设置普通字段的映射关系association:设置多对一的映射关系collection:设置一对多的映射关系属性:property:设置映射关系中实体类中的属性名column:设置映射关系中表中的字段名
--><resultMap id="userMap" type="User"><id property="id" column="id"></id><result property="userName" column="user_name"></result><result property="password" column="password"></result><result property="age" column="age"></result><result property="sex" column="sex"></result></resultMap><!--List<User> testMohu(@Param("mohu") String mohu);--><select id="testMohu" resultMap="userMap"><!--select * from t_user where username like '%${mohu}%'-->select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')</select>

若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)
此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
a> 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
b> 可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰
例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为
userName

 <settings><!--将下划线映射为驼峰--><setting name="mapUnderscoreTocamelcase" value="true"/></settins>

5.2 多对一映射处理

场景模拟:查询员工信息以及员工所对应的部门信息
一个员工对应一条部门信息,所以一个员工对应一个部门实体
一各部门对应多个员工信息,所以一个部门对应一个员工集合

员工类里面有属性:private Dept dept; // Dept类中包含id,dept_name等部门属性
对应了部门信息,此时搜索出来的sql信息中包含的部门信息不能和dept产生直接映射(因为属性不一样)
应该和dept中的属性进行映射,此时就需要自定义映射了
有以下方法进行处理

5.2.1 级联方式处理映射关系

<resultMap id="empDeptMap" type="Emp"> <id column="eid" property="eid"></id> <result column="ename" property="ename"></result><result column="age" property="age"></result><result column="sex" property="sex"></result><!--级联映射--><result column="did" property="dept.did"></result><result column="dname" property="dept.dname"></result>
</resultMap><!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
</select>

5.2.2 使用association处理映射关系(处理实体类类型的属性映射)

<resultMap id="empDeptMap" type="Emp"><id column="eid" property="eid"></id><result column="ename" property="ename"></result><result column="age" property="age"></result><result column="sex" property="sex"></result><!--property是实体类中属性名,javaType是该属性的全类名,这里已经提前设置过全类名为别名Dept了,在1.4中有提到--><association property="dept" javaType="Dept"><id column="did" property="did"></id><result column="dname" property="dname"></result></association></resultMap><!--Emp getEmpAndDeptByEid(@Param("eid") int eid);--><select id="getEmpAndDeptByEid" resultMap="empDeptMap">select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
</select>

5.2.3 分步查询

①查询员工信息

/*** 通过分步查询查询员工信息
* @param eid* @return 
*/Emp getEmpByStep(@Param("eid") int eid);
<resultMap id="empDeptStepMap" type="Emp"><id column="eid" property="eid"></id><result column="ename" property="ename"></result><result column="age" property="age"></result><result column="sex" property="sex"></result><!--select:设置分步查询,查询某个属性的值的 sql 的全类名.方法名(namespace.sqlId) column:将sql以及查询结果中的某个字段 设置为分步查询的条件,也就是相当于参数传递给下一个sql语句--><association property="dept" select="com.atguigu.MyBatis.mapper.DeptMapper.getEmpDeptByStep" column="did">     </association>
</resultMap><!--Emp getEmpByStep(@Param("eid") int eid);-->
<select id="getEmpByStep" resultMap="empDeptStepMap">select * from t_emp where eid = #{eid}
</select>

②根据员工所对应的部门id查询部门信息

/*** 分步查询的第二步: 根据员工所对应的did查询部门信息
* @param did* @return Dept 
*/Dept getEmpDeptByStep(@Param("did") int did)
 <!--Dept getEmpDeptByStep(@Param("did") int did);--><select id="getEmpDeptByStep" resultType="Dept">select * from t_dept where did = #{did}</select>

以上,就是
第一步:select * from t_emp where eid = #{eid}按员工id查询到员工信息,
第二步:将员工信息中的部门id作为参数传给 select * from t_dept where did = #{did},
第三步:将第二步查询到的结果返回给association中的property=“dept”

分布查询优点

分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。
此时可通过associationcollection中fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”

5.3 一对多映射处理

部门对应多个员工,所以部门类中有一个员工集合的属性List< Emp>

5.3.1 collection

/*** 根据部门id查新部门以及部门中的员工信息
* @param did* @return 
*/Dept getDeptEmpByDid(@Param("did") int did);
 <!--type是全类名--><resultMap id="deptEmpMap" type="Dept"><id property="did" column="did"></id><result property="dname" column="dname"></result><!--ofType:设置collection标签所处理的集合属性中 存储数据的类型 --><collection property="emps" ofType="Emp"><id property="eid" column="eid"></id><result property="ename" column="ename"></result><result property="age" column="age"></result><result property="sex" column="sex"></result></collection></resultMap><!--Dept getDeptEmpByDid(@Param("did") int did);--><select id="getDeptEmpByDid" resultMap="deptEmpMap">select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did = emp.did where dept.did = #{did}</select>

5.3.2 分步查询

①查询部门信息

/*** 分步查询部门和部门中的员工
* @param did* @return 
*/Dept getDeptByStep(@Param("did") int did);
<resultMap id="deptEmpStep" type="Dept"><id property="did" column="did"></id><result property="dname" column="dname"></result><!--fetchType:延迟查询select:设置分步查询,查询某个属性的值的 sql 的全类名.方法名(namespace.sqlId) column:将sql以及查询结果中的某个字段 设置为分步查询的条件,也就是相当于参数传递给下一个sql语句--><collection property="emps" fetchType="eager"select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" column="did"></collection>
</resultMap><!--Dept getDeptByStep(@Param("did") int did);--><select id="getDeptByStep" resultMap="deptEmpStep">select * from t_dept where did = #{did}</select>

②根据部门id查询部门中的所有员工

 /*** 根据部门id查询员工信息
* @param did* @return List<Emp>*/List<Emp> getEmpListByDid(@Param("did") int did);
<!--将查询道德结果赋值给第一步中的emps属性--><!--List<Emp> getEmpListByDid(@Param("did") int did);--><select id="getEmpListByDid" resultType="Emp">select * from t_emp where did = #{did}</select>

执行顺序查考5.2.3中的顺序

六、 动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决 拼接SQL语句字符串时的痛点问题

6.1 if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行

<!--List<Emp> getEmpListByCondition(Emp emp);--><select id="getEmpListByMoreTJ" resultType="Emp">select * from t_emp where 1=1 <if test="ename != '' and ename != null"> and ename = #{ename} </if> <if test="age != '' and age != null"> and age = #{age} </if> <if test="sex != '' and sex != null"> and sex = #{sex} </if> 
</select>

6.2 where

where和if一般结合使用:
a> 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
b> 若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:where标签不能去掉条件最后多余的and

<select id="getEmpListByMoreTJ2" resultType="Emp"> select * from t_emp <where> <if test="ename != '' and ename != null"> ename = #{ename} </if> <if test="age != '' and age != null"> and age = #{age} </if> <if test="sex != '' and sex != null"> and sex = #{sex} </if> </where> 
</select>

6.3 trim

trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容

<select id="getEmpListByMoreTJ" resultType="Emp">select * from t_emp<trim prefix="where" suffixOverrides="and"><if test="ename != '' and ename != null">ename = #{ename} and</if><if test="age != '' and age != null">age = #{age} and</if><if test="sex != '' and sex != null">sex = #{sex}</if></trim></select>

6.4 choose、when、otherwise

choose、when、 otherwise相当于if…else if…else

<!--List<Emp> getEmpListByChoose(Emp emp);--><select id="getEmpListByChoose" resultType="Emp">select <include refid="empColumns"></include> from t_emp<where><choose><when test="ename != '' and ename != null">ename = #{ename}</when><when test="age != '' and age != null">age = #{age}</when><when test="sex != '' and sex != null">sex = #{sex}</when><when test="email != '' and email != null">email = #{email}</when></choose></where></select>

6.5 foreach

 <!--int insertMoreEmp(List<Emp> emps);--><insert id="insertMoreEmp">insert into t_emp values<foreach collection="emps" item="emp" separator=",">(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)</foreach></insert><!--int deleteMoreByArray(int[] eids);--><delete id="deleteMoreByArray">delete from t_emp where<foreach collection="eids" item="eid" separator="or">eid = #{eid}</foreach></delete><!--int deleteMoreByArray(int[] eids);--><delete id="deleteMoreByArray">delete from t_emp where eid in<foreach collection="eids" item="eid" separator="," open="(" close=")"> #{eid}</foreach>
</delete>

6.6 SQL片段

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入,在映射

<sql id="empColumns">eid,ename,age,sex,did
</sql>select <include refid="empColumns"></include> from t_emp

七、 MyBatis的缓存

SqlSession 是 MyBatis 的核心接口之一,用于执行与数据库的交互操作。它提供了执行 SQL 语句的所有方法,包括插入、更新、删除和查询,还可以管理事务、获取映射器(Mapper)接口的实例等。

SqlSession 的主要功能包括:
执行SQL操作:如 insert、update、delete、select 等方法,用于执行对应的 SQL 语句。
事务管理:通过 commit() 和 rollback() 方法进行事务的提交与回滚。
获取Mapper:通过 getMapper(Class type) 方法获取映射器接口的实例,从而使用接口调用来执行 SQL。
缓存管理:SqlSession 还负责管理一级缓存,它会自动缓存相同会话中的查询结果,减少对数据库的访问。

7.1 MyBatis的一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问

使一级缓存失效的四种情况:

  1. 不同的SqlSession对应不同的一级缓存
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存

7.2 MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

二级缓存开启的条件:
a> 在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
b> 在映射文件中设置标签< cache/>
c> 二级缓存必须在SqlSession关闭或提交之后有效,关闭或提交之前,是保存在了一级缓存中,SqlSession关闭之后,一级缓存中的数据会写入二级缓存
d> 查询的数据所转换的实体类类型必须实现序列化的接口

使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

7.3 二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:

①eviction属性:缓存回收策略,默认的是 LRU。

  • LRU(Least Recently Used) 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK –弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

②flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

③size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出

④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

7.4 MyBatis缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存

7.5 整合第三方缓存EHCache

7.5.1、添加依赖

<!-- Mybatis EHCache整合包 --><dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.2.1</version></dependency><!-- slf4j日志门面的一个具体实现 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>

7.5.2 创建EHCache的配置文件ehcache.xml

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"><!-- 磁盘保存路径 --><diskStore path="D:\atguigu\ehcache"/><defaultCachemaxElementsInMemory="1000"maxElementsOnDisk="10000000"eternal="false"overflowToDisk="true"timeToIdleSeconds="120"timeToLiveSeconds="120"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"></defaultCache></ehcache>

7.5.3 设置二级缓存的类型

 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

7.5.4 加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml

 <?xml version="1.0" encoding="UTF-8"?><configuration debug="true"><!-- 指定日志输出的位置 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 日志输出的格式 --><!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 --><pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern></encoder></appender><!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR --> <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 --><root level="DEBUG"><!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender --><appender-ref ref="STDOUT" /></root><!-- 根据特殊需求指定局部日志级别 --><logger name="com.atguigu.crowd.mapper" level="DEBUG"/></configuration>

八、 Mybatis逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:

  • Java实体类
  • Mapper接口
  • Mapper映射文件

8.1 创建逆向工程的步骤

①添加依赖和插件

<!-- 依赖MyBatis核心包 -->
<dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- log4j日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency></dependencies><!-- 控制Maven在构建过程中相关配置 -->
<build><!-- 构建过程中用到的插件 --><plugins><!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><!-- 插件的依赖 --><dependencies><!-- 逆向工程的核心依赖 --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency></dependencies></plugin></plugins>
</build>

②创建MyBatis的核心配置文件
③创建逆向工程的配置文件

在resources目录下,文件名必须是:generatorConfig.xml

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!--targetRuntime: 执行生成的逆向工程的版本<1>MyBatis3Simple: 生成基本的CRUD(清新简洁版)<2>MyBatis3: 生成带条件的CRUD(奢华尊享版)--><context id="DB2Tables" targetRuntime="MyBatis3"><!-- 数据库的连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mybatis? serverTimezone=UTC"userId="root"password="123456"></jdbcConnection><!-- javaBean的生成策略--><javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!-- SQL映射文件的生成策略 --><sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\resources"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!-- Mapper接口的生成策略 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper"  targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- 逆向分析的表 --><!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --><!-- domainObjectName属性指定生成出来的实体类的类名 --><table tableName="t_emp" domainObjectName="Emp"/><table tableName="t_dept" domainObjectName="Dept"/></context></generatorConfiguration>

④执行MBG插件的generate目标
在这里插入图片描述
⑤效果
在这里插入图片描述

九、 分页查询

为了更高效和便捷地实现分页,MyBatis 社区开发了多种分页插件。这些插件通过拦截器(Interceptor)机制,在 SQL 执行前或执行后自动修改 SQL 语句或处理查询结果,实现数据库层面的分页。

分页插件的工作原理主要包括以下步骤:

  1. 拦截器机制:分页插件通过 MyBatis 的拦截器机制拦截执行 SQL 的方法,例如 Executor 接口中的 query 方法。通过拦截器,插件可以在 SQL 执行之前或执行之后对 SQL 语句进行修改。
  2. 自动添加分页语句:当拦截到查询方法时,分页插件会检测传入的参数是否包含分页信息(如 pageNumpageSize)。如果包含,插件会根据数据库类型自动为原始 SQL 语句添加相应的分页语句(如 LIMITOFFSETROWNUM 等)。
  3. 执行分页 SQL:经过插件修改的 SQL 会被执行器执行,数据库返回分页后的结果集。
  4. 封装结果:插件可以进一步封装查询结果,将其封装为分页对象,如 Page<T>,以便开发者方便地使用分页结果。

PageHelper:PageHelper 是 MyBatis 中最流行的分页插件。它通过自动拦截查询语句,添加 LIMITOFFSET 子句来实现分页,并且能够自动处理分页参数和结果集封装。

  1. 优点
  • 自动化:分页插件通过拦截和修改 SQL 语句,实现了自动分页,开发者无需手动编写分页 SQL。
  • 高效:插件直接在数据库层面实现分页,避免了内存分页的性能瓶颈。
  • 易用性:插件通常会封装分页结果,使得开发者可以方便地处理分页数据,如获取总记录数、总页数、当前页等信息。
  1. 缺点
  • 复杂性:分页插件增加了系统的复杂性,尤其是在处理复杂查询或特定数据库时,可能需要额外的配置或调试。
  • 依赖性:使用分页插件时,系统对插件产生了依赖性,如果插件更新或不再维护,可能会影响系统的稳定性。
  • 扩展性:有时插件可能不支持某些高级或自定义的分页需求,开发者需要自己扩展或修改插件代码。

分页插件的使用步骤

①添加依赖

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version>
</dependency>

②配置分页插件
在MyBatis的核心配置文件中配置插件

<plugins><!--设置分页插件--><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

分页插件的使用

a> 在查询功能之前使用Page< object> page=PageHelper.startPage(int pageNum, int pageSize)开启分页功能

  • pageNum:当前页的页码
  • pageSize:每页显示的条数

b> 在查询获取list集合之后,使用PageInfo< T> pageInfo = new PageInfo<>(List< T> list, int navigatePages)获取分页相关数

  • list:分页之后的数据
  • navigatePages:导航分页的页码数

c>分页相关数据
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]

相关文章:

【Mybatis】Mybatis基础

文章目录 前言一、搭建MyBatis1.1 创建maven工程1.2 加入log4j日志功能1.3 MyBatis的增删改查1.4 核心配置文件详解 二、MyBatis获取参数值的两种方式2.1 单个字面量类型的参数2.2 多个字面量类型的参数2.3 map集合类型的参数2.4 实体类类型的参数2.5 使用Param标识参数 三、 M…...

(002)Excel 使用图表,统计

第一步新建数据&#xff0c;将数据转成表格&#xff1a; 选中表格数据&#xff0c;右下角小图标&#xff1a;汇总 图表。...

云服务器主动防御策略与自动化防护(下)

三、纵深防御体系构建 1. 系统层防护 # 自动安全更新配置 sudo apt install unattended-upgrades sudo dpkg-reconfigure unattended-upgrades# 内核防护加固 sudo vim /etc/sysctl.conf# 添加以下参数&#xff1a; net.ipv4.conf.all.rp_filter1 net.ipv4.conf.default.rp_f…...

在前端应用领域驱动设计(DDD):必要性、挑战与实践指南

引言 领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称 DDD&#xff09;起源于后端复杂业务系统建模领域&#xff0c;是 Eric Evans 在 2003 年提出的一套理论体系。近年来&#xff0c;随着前端工程化与业务复杂度的持续提升&#xff0c;"前端也要 DDD&quo…...

【软件工程】需求分析详解

需求分析是确保软件产品符合用户期望、降低返工风险的关键环节。通过系统化的方法&#xff0c;团队可以从多渠道获取需求&#xff0c;利用多种建模技术对需求进行结构化分析&#xff0c;并编写规范的需求规格说明书&#xff08;SRS&#xff09;&#xff0c;最终通过评审、验证及…...

FPGA-DDS信号发生器

FPGA-DDS信号发生器 DDS基本原理 ​ FPGA实现的DDS&#xff08;直接数字频率合成&#xff09;波形生成器是一种高效、灵活的数字信号生成技术&#xff0c;广泛应用于通信、雷达和测试设备中。其核心原理是通过数字计算生成特定频率的波形。 ​ DDS通过相位累加、查找表(LUT)…...

二进制、高位低位、位移操作与进制转换全解

二进制、高位低位、位移操作与进制转换全解 在计算机科学中&#xff0c;理解高位与低位、左移与右移、进制转换与位运算非常重要。这篇文章用清晰直观的方式梳理这些基本概念。 高位与低位 低位&#xff1a;二进制中靠右的位&#xff0c;权值较小&#xff08;例如 (2^0, 2^1…...

docker存储

注意&#xff1a;数据卷挂载&#xff08;卷映射&#xff09;&#xff1a;Docker会自动创建数据卷&#xff0c;并将容器运行所需的文件复制到数据卷中。 目录挂载&#xff1a;如果宿主机上没有对应的目录&#xff0c;容器会因为缺少运行所需的文件而出错。 1.目录挂载 指令&am…...

回归预测 | Matlab实现DBO-LightGBM蜣螂算法优化轻量级梯度提升机多输入单输出回归预测,作者:机器学习之心

回归预测 | Matlab实现DBO-LightGBM蜣螂算法优化轻量级梯度提升机多输入单输出回归预测&#xff0c;作者&#xff1a;机器学习之心 目录 回归预测 | Matlab实现DBO-LightGBM蜣螂算法优化轻量级梯度提升机多输入单输出回归预测&#xff0c;作者&#xff1a;机器学习之心预测效果…...

[ 问题解决 ] sqlite3.ProgrammingError: SQLite objects created in a thread can ...

目录 为什么会出现这个问题&#xff1f; 解决方法一&#xff1a;每个请求新建自己的连接&#xff08;推荐&#xff09; 解决方法二&#xff1a;允许 SQLite 跨线程使用连接&#xff08;不推荐&#xff09; 小结 当你在 python 中使用 Flask 里面调用了数据库的操作的时候&a…...

AI智能体开发新范式:多智能体协作与自进化系统的构建之道

一、从单Agent到多Agent&#xff1a;为什么“群体智能”是必然&#xff1f; 复杂任务的分而治之案例&#xff1a; 电商大促活动的全自动运营商品Agent&#xff1a;实时调价&#xff08;根据库存/竞品&#xff09;用户Agent&#xff1a;生成千人千面推荐风控Agent&#xff1a;检…...

js补环境工具使用技巧、补环境实例、重点环境检测点详解

什么是补环境&#xff0c;模拟浏览器环境让浏览器js运行&#xff0c;为什么需要补环境&#xff0c;因为浏览器和本地nodejs环境有差异&#xff0c;网站开发者为了检测用户是否是本地环境运行 主要补的环境Document,Window,Navigator,Location,Element 这是内置原始类型&#…...

TF_LOG 配置及级别详解

以下是Terraform中TF_LOG配置及级别的详解&#xff1a; 配置方法 设置日志级别 通过设置TF_LOG环境变量来启用Terraform的日志功能&#xff0c;并指定日志级别。可以将该变量设置为以下值之一&#xff1a;TRACE、DEBUG、INFO、WARN、ERROR。其中&#xff0c;TRACE级别最为详…...

vue3使其另一台服务器上的x.html,实现x.html调用中的函数,并向其传递数据。

vue3例子 <template><div><iframeload"loadIFreamSite"id"loadIframeSite":src"iframeSrc1"frameborder"0"scrolling"no"allowtransparency"true"style"width: 100%"></iframe&g…...

英语五大基本句型

文章目录 一、主谓二、主谓宾三、主系表什么是什么什么怎么样系动词感官动词 一、主谓 构成&#xff1a;动作的发出者 动作 例句&#xff1a;I run.&#xff08;我跑步。&#xff09; 二、主谓宾 构成&#xff1a;动作的发出者 动作 动作的接受者 构成&#xff1a;主语&a…...

什么是 DDoS 攻击?高防 IP 如何有效防护?2025全面解析与方案推荐

一、DDoS 攻击&#xff1a;互联网时代的 “数字核武器” 1. DDoS 攻击的本质与原理 ** 分布式拒绝服务攻击&#xff08;DDoS&#xff09;** 通过操控海量僵尸设备&#xff0c;向目标服务器发送洪水般请求&#xff0c;耗尽带宽、连接或计算资源&#xff0c;导致合法用户无法访…...

论文速报《Enhancing Autonomous Driving Systems...:LLM-MPC混合架构增强自动驾驶》

论文链接&#xff1a;https://arxiv.org/pdf/2504.11514 代码链接&#xff1a;https://github.com/ForzaETH/LLMxRobot 0. 简介 自动驾驶领域的传统方法多依赖于数据驱动模型&#xff0c;通过大量标注数据训练实现路径规划和控制。然而&#xff0c;现实世界中道路临时施工、突…...

Nacos 3.0 上线 MCP Registry,支持 MCP 服务注册到发现全流程管理

Nacos 3.0 正式版本发布啦&#xff01;升级 MCP Registry&#xff0c;围绕着 MCP&#xff08;Model Context Protocol&#xff09; 服务管理&#xff0c;MCP 多种类型注册&#xff0c;包含 MCP Server 注册、编排、动态调试和管理&#xff0c;并且提供 Nacos-MCP-Router 可以进…...

一文解析大语言模型量化技术

目录 一、为什么需要量化技术 1、数据规模 2、32位浮点数&#xff08;FP32&#xff09; 3、16位浮点数&#xff08;FP16&#xff09; 4、Bfloat16&#xff08;BF16&#xff09; 5.INT8&#xff08;8位整数&#xff09;和INT4&#xff08;4位整数&#xff09; 总结&#…...

使用python实现自动化拉取压缩包并处理流程

使用python实现自动化拉取压缩包并处理流程 实现成果展示使用说明 实现成果展示 使用说明 执行./run.sh 脚本中的内容主要功能是&#xff1a; 1、从远程服务器上下拉制定时间更新的数据 2、将数据中的zip拷贝到指定文件夹内 3、解压后删除所有除了lcm之外的文件 4、新建一个ou…...

解构编程语言的基因密码:论数据类型如何被语言系统定义与重塑

摘要 本文从理论与实践层面系统探讨编程语言中数据类型的定义、实现与演化。通过静态与动态类型系统的差异分析&#xff0c;结合案例、流程图和表格&#xff0c;全面呈现主流语言数据类型设计特点及其对内存管理、错误防范与性能优化的影响。文章旨在为语言设计者和开发者提供…...

GRPO vs SFT:强化学习提升大模型多模态推理泛化能力的原因研究

GRPO vs SFT&#xff1a;强化学习提升大模型多模态推理泛化能力的原因研究 作者&#xff1a;吴宇斌 原文地址&#xff1a;https://zhuanlan.zhihu.com/p/1892362859628963761 训练目标与优化方式差异对比 监督微调&#xff08;SFT&#xff09;的目标&#xff1a; SFT使用带标注…...

从千兆到40G:飞速(FS)助力制造企业构建高可靠智能生产网络

案例亮点 部署S5850-24S2Q交换机&#xff0c;启用MLAG跨设备链路聚合&#xff0c;构建高性能冗余架构&#xff0c;消除单点故障风险&#xff0c;将网络可用性提升至99.99%&#xff0c;保障生产系统与全球业务连续性。采用40G光模块与US Conec MTP连接头多模跳线实现数据中心间…...

WHAT - 《成为技术领导者》思考题(第三章)

文章目录 涉及内容理解问题管理想法的交流保证质量 思考题思路和示例框架1. 观察一个你认为是领导者的人&#xff0c;列出他的行为&#xff0c;分类&#xff0c;并思考自己未采用的行为2. 观察一个不太像领导者的人&#xff0c;列出错过的简单机会&#xff0c;并反思3. 让别人注…...

Go 语言入门:(一) 环境安装

一、前言 这里不同于其他人的 Go 语言入门&#xff0c;环境安装我向来注重配置&#xff0c;比如依赖包、缓存的默认目录。因为前期不弄好&#xff0c;后面要整理又影响这影响那的&#xff0c;所以就干脆写成文章&#xff0c;方便后期捡起。 二、安装 1. 安装包 https://go.…...

GTC2025全球流量大会:领驭科技以AI云端之力,助力中国企业出海破浪前行

在全球化与数字化浪潮下&#xff0c;AI技术正成为中国企业出海的重要驱动力。一方面&#xff0c;AI通过语言处理、数据分析等能力显著提升出海企业的运营效率与市场适应性&#xff0c;尤其在东南亚等新兴市场展现出"高性价比场景适配"的竞争优势&#xff1b;另一方面…...

013几何数学——算法备赛

几何数学 平面切分 蓝桥杯2020年省赛题 问题描述 平面上有N条直线&#xff0c;其中第i条直线为yAxB.请计算这些直线将平面分成了几个部分&#xff1f; 输入 第一行输入一个N&#xff0c;接下来N行输入两个整数代表Ai和Bi。 1<N<10^5. 思路分析 初始时一条直线将…...

VUE3:封装一个评论回复组件

之前用React封装的评论回复组件&#xff0c;里面有三个主要部分&#xff1a;CommentComponent作为主组件&#xff0c;CommentItem处理单个评论项&#xff0c;CommentInput负责输入框。现在需要将这些转换为Vue3的组件。 Vue3和React在状态管理上有所不同&#xff0c;Vue3使用r…...

DELL R740服务器闪黄灯不开机故障案例

1&#xff1a;DELL R740服务器 2&#xff1a;东莞长安客户工厂晚上十一二点电路跳闸多次&#xff0c;导致R740 ERP服务器无法开机。 3&#xff1a;故障现象为&#xff1a;主机能正常通电&#xff0c;开机按钮无通电迹象&#xff0c;正常情况会闪绿灯慢闪&#xff0c;通电一会后…...

记录一下QA(from deepseek)

Q1:__init__.py文件 在 Python 中&#xff0c;当你在一个目录下创建 __init__.py 文件时&#xff0c;这个目录会被视为一个 包&#xff08;Package&#xff09;。包的存在使得 Python 能够通过点号&#xff08;.&#xff09;层级式地组织模块&#xff08;.py 文件&#xff09;&…...

码蹄集——进制输出、求最大公约数、最小公倍数

进制乱炖 本题考查输出的进制转换&#xff0c;可以直接使用c里的format格式输出 #include<iostream> #include<algorithm> #include<string> using namespace std;int main() {int x;cin>>x;printf("%d %o %x %u\n",x,x,x,x);//十进制 八进…...

从技术走向管理:带来哪些角色转变与挑战

文章目录 一、从技术到管理1、从技术转到管理的优劣势&#xff08;1&#xff09;优势&#xff08;2&#xff09;劣势 2、刚转岗容易犯的几个问题3、最大的变化&#xff1a;不再是一个人单打独斗4、警惕&#xff1a;一开始不要把“人”过早的介入到“事”5、如何完成角色的转变&…...

C语言-指针(一)

目录 指针 内存 概念 指针变量 取地址操作符&#xff08;&&#xff09; 操作符“ * ” 指针变量的大小 注意 指针类型的意义 作用 void * 指针 const修饰指针变量 const放在*前 const放在*后 双重const修饰 指针的运算 1.指针 - 整数 2.指针 - 指针 3.指…...

Python面试问题

一、Python 基础 1. Python 的特点 动态类型&#xff1a;变量无需声明类型。解释型语言&#xff1a;逐行解释执行。支持多种编程范式&#xff08;面向对象、函数式、过程式&#xff09;。 2. 列表&#xff08;List&#xff09;与元组&#xff08;Tuple&#xff09;的区别 特…...

RAG工程-基于LangChain 实现 Advanced RAG(预检索优化)

Advanced RAG 概述 Advanced RAG 被誉为 RAG 的第二范式&#xff0c;它是在 Naive RAG 基础上发展起来的检索增强生成架构&#xff0c;旨在解决 Naive RAG 存在的一些问题&#xff0c;如召回率低、组装 prompt 时的冗余和重复以及灵活性不足等。它重点聚焦在检索增强&#xff0…...

【时时三省】(C语言基础)循环结构程序设计习题1

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 习题1 输入两个正整数m和n&#xff0c;求其最大公约数和最小公倍数。 解题思路&#xff1a; 求两个正整数 m 和 n 的最大公约数通常使用辗转相除法&#xff08;欧几里得算法&#xff…...

[密码学实战]SDF之设备管理类函数(一)

[密码学实战]SDF之设备管理类函数(一) 一、标准解读:GM/T 0018-2023核心要求 1.1 SDF接口定位 安全边界:硬件密码设备与应用系统间的标准交互层功能范畴: #mermaid-svg-s3JXUdtH4erONmq9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16p…...

CDGP|如何建立高效的数据治理团队?

近年来&#xff0c;数据治理行业迅速发展&#xff0c;越来越多的企业开始重视并投入大量资源来建立和完善数据治理体系。数据治理体系不仅能够帮助企业更好地管理和利用数据资源&#xff0c;提升数据质量和数据价值&#xff0c;还能够为企业带来竞争优势和可持续发展能力。 然…...

如何评价 DeepSeek 的 DeepSeek-V3 模型?

DeepSeek-V3 是由杭州 DeepSeek 公司于 2024 年 12 月 26 日发布的一款开源大语言模型&#xff0c;其性能和创新技术在国内外引起了广泛关注。从多个方面来看&#xff0c;DeepSeek-V3 的表现令人印象深刻&#xff0c;具体评价如下&#xff1a; 性能卓越 DeepSeek-V3 拥有 6710 …...

【基础篇】prometheus命令行参数详解

文章目录 本篇内容讲解命令行参数详解 本篇内容讲解 prometheus高频修改命令行参数详解 命令行参数详解 在页面的/页面上能看到所有的命令行参数&#xff0c;如图所示&#xff1a; 使用shell命令查看 # ./prometheus --help usage: prometheus [<flags>]The Promethe…...

SpringBoot实现接口防刷的5种高效方案详解

目录 前言&#xff1a;接口防刷的重要性 方案一&#xff1a;基于注解的访问频率限制 实现原理 核心代码实现 使用示例 优缺点分析 方案二&#xff1a;令牌桶算法实现限流 算法原理 核心实现 配置使用 适用场景分析 方案三&#xff1a;分布式限流&#xff08;Redis …...

DeepSearch复现篇:QwQ-32B ToolCall功能初探,以Agentic RAG为例

DeepSearch复现篇&#xff1a;QwQ-32B ToolCall功能初探&#xff0c;以Agentic RAG为例 作者&#xff1a;CyPaul Space 原文地址&#xff1a;https://zhuanlan.zhihu.com/p/30289363967 全文阅读约3分钟~ 背景 今天看到 论文&#xff1a;Search-R1: Training LLMs to Reason …...

项目实战-贪吃蛇大作战【补档】

这其实算是一个补档&#xff0c;因为这个项目是我在大一完成的&#xff0c;但是当时没有存档的习惯&#xff0c;今天翻以前代码的时候翻到了&#xff0c;于是乎补个档&#xff0c;以此怀念和志同道合的网友一起做项目的日子 ₍ᐢ ›̥̥̥ ༝ ‹̥̥̥ ᐢ₎♡ 这里面我主要负责…...

power bi获取局域网内共享文件

power bi获取局域网内共享文件 需求&#xff1a; 数据源并不一定都是在本地&#xff0c;有可能在云端&#xff0c;也有可能在其他服务器&#xff0c;今天分享如果数据源在另外一台服务器&#xff0c;如何获取数据源的方法。 明确需求&#xff1a;需要通过PowerBI获取局域网中的…...

100%提升信号完整性:阻抗匹配在高速SerDes中的实践与影响

一个高速信号SerDes通道&#xff08;例如PCIe、112G/224G-PAM4&#xff09;包含了这些片段&#xff1a; 传输线连通孔&#xff08;PTH or B/B via&#xff09;连接器高速Cable锡球&#xff08;Ball and Bump&#xff09; 我们会希望所有的片段都可以有一致的阻抗&#xff0c;…...

第六章:Tool and LLM Integration

Chapter 6: Tool and LLM Integration 从执行流到工具集成&#xff1a;如何让AI“调用真实世界的技能”&#xff1f; 在上一章的执行流框架中&#xff0c;我们已经能让多个代理协作完成复杂任务。但你是否想过&#xff1a;如果用户要求“查询实时天气”或“打开网页搜索”&…...

prompt提示词编写技巧

为什么学习prompt编写 目的&#xff1a;通过prompt的编写&#xff0c;提升LLM输出相关性、准确性和多样性&#xff0c;并对模型输出的格式进行限制&#xff0c;满足我们的业务需求。 学过提示词工程的人&#xff1a;像“专业导演”&#xff0c;通过精准指令控制 AI 输出&#…...

Nginx配置SSL详解

文章目录 Nginx配置SSL详解1. SSL/TLS 基础知识2. 准备工作3. 获取SSL证书4. Nginx SSL配置步骤4.1 基础配置4.2 配置说明 5. 常见配置示例5.1 双向认证配置5.2 多域名SSL配置 6. 安全优化建议7. 故障排查总结参考资源下载验证的完整实例 Nginx配置SSL详解 1. SSL/TLS 基础知识…...

网络安全之红队LLM的大模型自动化越狱

前言 大型语言模型&#xff08;LLMs&#xff09;已成为现代机器学习的重要支柱&#xff0c;广泛应用于各个领域。通过对大规模数据的训练&#xff0c;这些模型掌握了多样化的技能&#xff0c;展现出强大的生成与理解能力。然而&#xff0c;由于训练数据中难以完全剔除有毒内容&…...

【技术笔记】通过Cadence Allegro创建一个PCB封装(以SOT23为例)

【技术笔记】通过Cadence Allegro创建一个PCB封装&#xff08;以SOT23为例&#xff09; 一、焊盘创建二、PCB封装设计三、丝印位号及标识添加 更多内容见专栏&#xff1a;【硬件设计遇到了不少问题】、【Cadence从原理图到PCB设计】 一、焊盘创建 首先要找到元器件的相关手册&…...