MyBatis详细学习笔记

news2024/9/24 9:24:17

一、MyBatis简介

MyBatis是ORM框架,即对象关系映射框架。

二、搭建MyBatis

不同的MySQL版本使用的JDBC不同

com.mysql.jdbc.Driver // MySQL 5
com.mysql.cj.jdbc.Driver // MySQL 8

不同版本的MySQL的url也不同

jdbc:mysql://localhost:3306/ssm // MySQL 5
jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC // MySQL 8

三、快速开始

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>

2、编写MyBatis配置文件

作用:1. 配置链接数据库的环境 2. 配置MyBatis

放置位置:src/main/resources

<?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>
    <!-- 配置连接数据库的环境 -->
    <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="lukeewin"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 引入MyBatis的映射文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

3、Mapper接口

相当于DAO,但是不用创建实现类,MyBatis会创建代理类,并执行映射文件当中的SQL。

起名规则:POJO+Mapper

public interface UserMapper {

    int insertUser();
}

4、创建MyBatis的映射文件

Mapper 接口当中的一个抽象方法对应映射文件当中的一个SQL语句。

起名规则:POJO名字 + Mapper.xml

放置位置:src/main/resources/mappers/UserMapper.xml

映射关系:

image-20221123174559021

<?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">
<mapper namespace="top.lukeewin.mybatis.mapper.UserMapper">
    <!--
        mapper 接口和映射文件要保持两个一致
        1. mapper 接口的全类名和映射文件的 namespace 一致
        2. mapper 接口中的方法的方法名要和映射文件中的 sql 的 id 保持一致
    -->
    <!-- int insertUser() -->
    <insert id="insertUser">
        insert into t_user values(null, 'admin', '123456', 23, '男', '123456@qq.com')
    </insert>
</mapper>

5、测试

openSession() 获得 SqlSession默认是不会自动提交事务,因此需要自己手动提交。

openSession(true) 获得 SqlSession默认自动提交事务。

public class MyBatisTest {

    @Test
    public void testInsert() throws IOException {
        // 1. 获取核心配置文件的输入流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        // 2. 获取 SqlSessionFactoryBuilder 对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 3. 获取 SqlSessionFactory 对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        // 4. 获取 sql 的会话对象 SqlSession ,是 MyBatis 提供的操作数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5. 获取 UserMapper 的代理实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        // 6. 调用 mapper 接口中的方法,实现添加用户信息的功能
        int result = mapper.insertUser();
        System.out.println("结果:" + result);
        // 7. 提交事务,事务是不会自动提交的,需要手动提交事务
        sqlSession.commit();
        // 8. 关闭 sqlSession,最后一定要记得关闭会话
        sqlSession.close();
    }
}

6、添加日志功能

<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

resources/log4j.xml

<?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="%-5d %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>

    <!-- 默认配置,级别为debug 且根据name为log.console和 log.file两个appender输出-->
    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

在MyBatis核心配置文件中设置开启日志功能

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>

四、核心配置文件详解

核心配置文件必须按照一定的顺序写,否则会报错。

properties,settings,typeAliases,typeHandlers,
objectFactory,objectWrapperFactory,reflectorFactory,
plugins,environments,databaseIdProvider,mappers

1、引入properties文件

使用properties标签引入properties文件,此后可以在当前文件中使用${key}的方式访问properties中的value

<properties resource="jdbc.properties"/>

2、起别名

使用typeAliases标签可以给实体类起别名。

方式一:可以使用typeAlias中的type的值是指定给哪个类起别名,而alias的值是指别名,如果不写alias,那么有默认别名,默认别名为不区分大小写的类名。

方式二:可以使用package指定给哪个包路径下的类起别名。

<typeAliases>
        <!--
            alias的值为别名,可以不设置,如果不设置则有默认的别名,默认别名分为类名且不区分大小写
         -->
        <!--<typeAlias type="top.lukeewin.mybatis.pojo.User" alias="abc"/>-->
        <!--<typeAlias type="top.lukeewin.mybatis.pojo.User"/>-->
        <!-- 通过包设置类型别名,则指定包下的所有类将拥有默认别名 -->
        <package name="top.lukeewin.mybatis.pojo"/>
</typeAliases>

3、配置连接数据库环境

可以定义多个环境,切换时在emvironments中通过default来指定。

<environments default="development">
        <!-- 可以定义多个环境 -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!-- 数据源 -->
            <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/ssm?serverTimezone=UTC"/>
                <property name="username" value="lukeewin"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
</environments>

transactionManager: 定义事务管理器

​ type: 指定使用哪种事务管理器,有JDBC和MANGAED两种。

​ 其中JDBC是原生的事务管理方式。

​ MANGAED是被管理的意思,比如被Spring管理。

dataSource: 数据源

​ type: 设置数据源的类型

​ type=“POOLED|UNPOOLED|JNDI”

​ POOLED: 表示使用数据库连接池

​ UNPOOLED: 不使用数据库连接池

​ JNDI: 表示使用上下文中的数据源

4、引入映射文件

有两种方式:

方式一:单个文件引入,不推荐。

方式二:通过包路径方式引入,推荐。

​ 通过包路径的方式引入需要注意包路径必须和 mapper 接口路径一致,并且名字也必须要和 mapper接口的名字一致。

<mappers>
    <!--<mapper resource="mappers/UserMapper.xml"/>-->
    <!--
        以包的方式引入映射文件,但是必须要满足两个条件:
        1. mapper 接口和映射文件所在的包名必须一致
        2. mapper 接口的名字和映射文件的名字必须一致
    -->
    <package name="top.lukeewin.mybatis.mapper"/>
</mappers>

五、MyBatis获取参数的方式

有两种方式:${}和#{}

${}字符串拼接

#{}占位符

推荐使用#{}

因为占位符能避免SQL注入,同时可以为字符串和日期自动添加单引号。

1、单个字面量类型

若 mapper 接口方式的参数为单个的字面量类型(字符串、基本数据类型、包装类)

#{}${}:任意内容

注意:${}不会自动添加单引号

User getUserByUsername(String username);
<select id="getUserByUsername" resultType="User">
	select * from t_user where username = #{username}
</select>
<select id="getUserByUsername" resultType="User">
	select * from t_user where username = '${username}'
</select>

2、多个字面量类型

当 Mapper 接口中有多个参数的时候,MyBatis 会创建Map ,并使用 paramX 或 argX 为Key,参数值为 Value , 且两者均可混合使用。

User checkLogin(String username, String password);
<select id="checkLogin" resultType="User">
	select * from t_user where username = #{arg0} and password = #{arg1}
</select>
<select id="checkLogin" resultType="User">
	select * from t_user where username = #{param1} and password = #{param2}
</select>

3、以Map集合的方式传值

/**
 * {username: "xxxx"}
 * {password: "xxxx"}
 * @param map
 * @return
 */
User checkLoginByMap(Map<String, Object> map);
<!-- User checkLoginByMap(Map<String, Object> map) -->
<select id="checkLoginByMap" resultType="user">
    SELECT * FROM t_user WHERE username = #{username} and password = #{password};
</select>

4、参数为实体类(常用)

通过#{}或${}访问实体类中的属性

<!-- void insertUser(User user) -->
<insert id="insertUser">
	insert into t_user values(null, #{username}, #{password}, #{age}, #{gender}, #{email})
</insert>

5、通过@Param注解方式传参(常用)

在 mapper 接口中的方法形参中添加@Param注解指定map中的key

会替换原来的argX,以@Param中的值作为map中的key

User checkLoginByParam(@Param("username") String username, @Param("password") String password);
<select id="checkLoginByParam" resultType="User">
	select * from t_user where username = #{username} and password = #{password}
</select>
<select id="checkLoginByParam" resultType="User">
	select * from t_user where username = #{param1} and password = #{param2}
</select>

推荐:除了实体类型为,推荐使用@Param

六、MyBatis中的各种查询功能

1、返回单个实体类对象

User getUserById(@Param("id") Integer id);
<select id="getUserById" resultType="User">
	select * from t_user where id = #{id}
</select>

如返回了多条记录,则会报错。

image-20221126213114416

2、返回多条记录

若SQL语句查询的结果为多条时,一定不能使用实体类型接收,否则会报异常。

要有集合接收。

若SQL语句查询的结果返回一条时,可以使用集合接收。

<!-- List<User> getAllUser() -->
<select id="getAllUser" resultType="User">
    select * from t_user
</select>

3、查询单个数据

类型别名

java.lang.Integer-->int|integer

int-->_int|_integer

Map-->map

List-->list

Integer getCount();
<select id="getCount" resultType="int">
    select count(0) from t_user
</select>

4、查询一条记录

查询的结果没有对应的实体类的时候,就可以使用Map集合。

resultType 设置成 map 即可。

查询为null 的字段是不会放到Map集合里面。

Map<String, Object> getUserByIdToMap(@Param("id") Integer id);
<!-- Map<String, Object> getUserByIdToMap(@Param("id") Integer id) -->
<select id="getUserByIdToMap" resultType="map">
	select * from t_user where id = #{id}
</select>

5、查询多条记录

5.1、使用List集合

把Map集合放到List集合中。

List<Map<String, Object>> getAllUserToMap();
<select id="getAllUserToMap" resultType="map">
    select * from t_user
</select>

5.2、使用@MapKey

可以将每条数据转换为 map 集合放在一个大的 map 中,但必须要通过 @MapKey 注解将查询的某个字段的值作为大的 map 的键。

@MapKey("id")
Map<String, Object> getAllUserToMap();
<select id="getAllUserToMap" resultType="map">
    SELECT * FROM t_user
</select>
{2={password=123456, gender=, id=2, age=23, email=123456@qq.com, username=admin},
4={password=123456, gender=, id=4, age=23, email=123456@qq.com, username=admin}, 
5={password=123456, gender=, id=5, age=23, email=123456@qq.com, username=admin},
6={password=123456, gender=, id=6, age=23, email=123456@qq.com, username=admin},
7={password=123456, gender=, id=7, age=23, email=123456@qq.com, username=admin},
8={password=123456, gender=, id=8, age=23, email=123456@qq.com, username=admin},
9={password=123456, gender=, id=9, age=23, email=123456@qq.com, username=admin},
10={password=123456, gender=, id=10, age=23, email=123456@qq.com, username=admin},
11={password=123456, gender=, id=11, age=23, email=123456@qq.com, username=admin},
12={password=123456, gender=, id=12, age=23, email=123456@qq.com, username=admin},
15={password=123456, gender=, id=15, age=25, email=12345678@qq.com, username=赵丽颖},
16={password=123, gender=, id=16, age=25, email=12345678@qq.com, username=迪丽热巴},
17={password=123456, gender=, id=17, age=25, email=12345678@qq.com, username=高圆圆},
18={password=123456, gender=, id=18, age=23, email=123456@qq.com, username=admin},
19={password=123456, gender=, id=19, age=33, email=123456@qq.com, username=root}}

6、模糊查询

有三种方案

方案一:使用${}

方案二:使用concat(‘%’, #{mohu}, ‘%’)函数进行字符串拼接

方案三:使用"%“#{mohu}”%"

<!-- List<User> getUserByLike(@Param("mohu") String mohu -->
<select id="getUserByLike" 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>

七、批量删除

<!-- void deleteUserByBatch(@Param("ids") String ids) -->
<delete id="deleteMoreUser">
	delete from t_user where id in(${ids})
</delete>

八、动态设置表名

表名不能用单引号,所以不能用#{}

<!-- List<User> getUserList(@Param("tablename") String tablename) -->
<select id="getUserList" resultType="User">
    select * from ${tablename}
</select>

九、获取自增主键

void insertUser()返回的是受影响的行数,不能使用返回值返回主键

useGeneratedKeys:表示是否使用自增主键

keyProperty:指定获取到的主键存储到实体中的哪个属性中

void insertUser(User user);
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into t_user values(null, #{username}, #{password}, #{age}, #{gender}, #{email})
</insert>
@Test
public void testInsertUser() {
	SqlSession sqlSession = SqlSessionUtil.getSqlSession();
	SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
	User user = new User(null, "xiaoming", "123456", 23, "男", "123456@qq.com");
	mapper.insertUser(user);
	System.out.println(user);
}

十、自定义映射

字段名和属性名不一致

方式一:使用别名

Emp getEmpByEmpId(@Param("empId") Integer empId);
<select id="getEmpByEmpId" resultType="Emp">
    select emp_id empId, emp_name empName, age, gender from t_emp where emp_id = #{empId}
</select>

方式二:在 MyBatis核心配置文件中配置字段下划线自动转属性驼峰

<settings>
  <!-- 下划线 自动映射 驼峰 -->
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

方式三:使用resultMap

id: 唯一标识

type: 映射到哪个实体类

id标签: 主键的映射关系

result标签: 普通字段和属性之间的映射关系

column: 查询出来对应的字段名

property: 映射到实体中的属性名

<resultMap id="empResultMap" type="Emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
</resultMap>

<select id="getEmpByEmpId" resultMap="empResultMap">
    select * from t_emp where emp_id = #{empId}
</select>

1、多对一

多个 emp 对一个 dept

public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    private Dept dept;
    
    // getter/setter/toString
}
Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);

1.1、使用级联的方式

<resultMap id="empResultMap" type="Emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
    <result column="dept_id" property="dept.deptId"/>
    <result column="dept_name" property="dept.deptName"/>
</resultMap>

<!-- Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId) -->
<select id="getEmpAndDeptByEmpId" resultMap="empResultMap">
    select t_emp.*, t_dept.dept_name
    from t_emp
    left join t_dept
    on t_emp.dept_id = t_dept.dept_id
    where t_emp.emp_id = #{empId}
</select>

1.2、使用association标签

association:专门处理多对一的映射关系(处理实体类类型的属性)

property:属性名

javaType:属性的类型

<resultMap id="empResultMap" type="Emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
    <association property="dept" javaType="Dept">
        <id column="dept_id" property="deptId"/>
        <result column="dept_name" property="deptName"/>
    </association>
</resultMap>

1.3、分步查询

property:属性名

select:第二步查询的唯一标识

column:上一步查询出来的字段传递到下一步

注意:必须要在 MyBatis 核心配置文件中开启下划线自动映射驼峰,如果不开启,那么获取不了部门信息

/**
 * 通过分步查询来查询员工以及员工所对应的部门信息的第一步
 * @param empId
 * @return
 */
Emp getEmpAndDeptByEmpIdOne(@Param("empId") Integer empId);
/**
 * 通过分步查询员工以及员工所对应的部门信息的第二步
 * @param deptId
 * @return
 */
Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);

第一步:

<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
    <association property="dept"
                 select="top.lukeewin.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="dept_id"/>
</resultMap>
<!-- Emp getEmpAndDeptByEmpIdOne(@Param("empId") Integer empId) -->
<select id="getEmpAndDeptByEmpIdOne" resultMap="empAndDeptByStepResultMap">
    select * from t_emp where emp_id = #{empId}
</select>

第二步:

<!-- Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId) -->
<select id="getEmpAndDeptByStepTwo" resultType="Dept">
    select * from t_dept where dept_id = #{dept_id}
</select>

1.3.1、延迟加载

在 MyBatis 核心配置文件中开启延迟加载

全局性

aggressiveLazyLoading和lazyLoadingEnabled共同决定延迟加载

<settings>
    <!-- 开启延迟加载 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 按需加载 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

局部性

fetchType=“eager|lazy”

eager:立即迟加载

lazy:延迟加载

<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
    <association property="dept"
                 select="top.lukeewin.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="dept_id"
                 fetchType="lazy"
    />
</resultMap>

2、一对多

2.1、使用collection标签

collection:一对多(集合)

ofType:对应集合中泛型的类型

public class Dept {

    private Integer deptId;

    private String deptName;

    private List<Emp> emps;
    
    // 省略构造器,setter,getter,toString方法
}
Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);
<resultMap id="empResultMap" type="Dept">
    <id column="dept_id" property="deptId"/>
    <result column="dept_name" property="deptName"/>
    <collection property="emps" ofType="Emp">
        <id column="emp_id" property="empId"/>
        <result column="emp_name" property="empName"/>
        <result column="age" property="age"/>
        <result column="gender" property="gender"/>
    </collection>
</resultMap>
<!-- Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId) -->
<select id="getDeptAndEmpByDeptId" resultMap="empResultMap">
    select *
    from t_dept
    left join t_emp
    on t_dept.dept_id = t_emp.dept_id
    where t_dept.dept_id = #{deptId}
</select>

2.2、使用分步查询

先根据传递过来的部门 id 在部门表中查询,如果查到了就根据查询出来的部门 id 在用户表中查询对应有哪些用户

DeptMapper.java

/**
 * 通过分步查询查询部门以及部门的员工信息第一步
 * @param deptId
 * @return
 */
Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);

EmpMapper.java

/**
 * 通过分步查询查询部门以及部门的员工信息第二步
 * @param deptId
 * @return
 */
List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);

DeptMapper.xml

<resultMap id="deptAndEmpResultMapByStep" type="Dept">
    <id column="dept_id" property="deptId"/>
    <result column="dept_name" property="deptName"/>
    <collection property="emps"
                select="top.lukeewin.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                column="dept_id"/>
</resultMap>
<!-- Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId) -->
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
    select * from t_dept where dept_id = #{deptId}
</select>

EmpMapper.xml

<!-- List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId) -->
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
    select * from t_emp where dept_id = #{deptId}
</select>

3、多对多

多对多

十一、动态SQL

1、if

通过 test 属性中的表达式判断标签中的内容是否有效(是否会拼接到 sql 中)

/**
 * 根据条件查询员工信息
 * @param emp
 * @return
 */
List<Emp> getEmpByCondition(Emp emp);
<!-- List<Emp> getEmpByCondition(Emp emp) -->
<select id="getEmpByCondition" resultType="Emp">
    select *
    from t_emp
    where
    <if test="empName != null and empName != ''">
        emp_name = #{empName}
    </if>
    <if test="age != null and age != ''">
        and age = #{age}
    </if>
    <if test="gender != null and gender != ''">
        and gender = #{gender}
    </if>
</select>

2、where

where 1 = 1

<!-- List<Emp> getEmpByCondition(Emp emp) -->
<select id="getEmpByCondition" resultType="Emp">
    select *
    from t_emp
    where 1 = 1
    <if test="empName != null and empName != ''">
        and emp_name = #{empName}
    </if>
    <if test="age != null and age != ''">
        and age = #{age}
    </if>
    <if test="gender != null and gender != ''">
        and gender = #{gender}
    </if>
</select>

作用:可以自动去掉内容前多余的 and ,不会自动去掉内容后多余的 and

<!-- List<Emp> getEmpByCondition(Emp emp) -->
<select id="getEmpByCondition" resultType="Emp">
    select *
    from t_emp
    <where>
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </where>
</select>

3、trim

prefix:在前面添加内容

suffix:在后面添加内容

prefix:覆盖前面的内容

suffixOverrives:覆盖后面的内容

<!-- List<Emp> getEmpByCondition(Emp emp) -->
<select id="getEmpByCondition" resultType="Emp">
    select *
    from t_emp
    <trim prefix="where" suffixOverrides="and">
        <if test="empName != null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age != null and age != ''">
            age = #{age} and
        </if>
        <if test="gender != null and gender != ''">
            gender = #{gender}
        </if>
    </trim>
</select>

4、choose、when、otherwise

类似 if-else if-else

多选一

<!-- List<Emp> getEmpByChoose(Emp emp) -->
<select id="getEmpByChoose" resultType="Emp">
    select * from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                age = #{age}
            </when>
            <when test="gender != null and gender != ''">
                gender = #{gender}
            </when>
        </choose>
    </where>
</select>

5、foreach

作用:批量添加或批量删除

collection:设置要循环的数组或集合

item:要循环的每一个元素

separator:分隔符

open:以什么开头

close:以什么结束

index:索引

批量添加

<!-- void insertMoreEmp(@Param("emps") List<Emp> emps) -->
<insert id="insertMoreEmp">
    insert into t_emp values
    <foreach collection="emps" item="emp" separator=",">
        (null, #{emp.empName}, #{emp.age}, #{emp.gender}, null)
    </foreach>
</insert>

批量删除

方式一:

<!-- void deleteMoreEmp(@Param("empIds") Integer[] empIds) -->
<delete id="deleteMoreEmp">
    delete from t_emp where emp_id in
    <foreach collection="empIds" item="empId" separator="," open="(" close=")">
        #{empId}
    </foreach>
</delete>

方式二:

<!-- void deleteMoreEmp(@Param("empIds") Integer[] empIds) -->
<delete id="deleteMoreEmp">
    delete from t_emp where
    <foreach collection="empIds" item="empId" separator="or">
        emp_id = #{empId}
    </foreach>
</delete>

6、sql

作用:将重复的 SQL 代码抽取出来被多条语句重复使用

include 标签中的 refid 指定要使用 SQL 代码段的 id

<sql id="empColumns">
    emp_id,emp_name,age,gender,dept_id
</sql>
<!-- List<Emp> getEmpByCondition(Emp emp) -->
<select id="getEmpByCondition" resultType="Emp">
    select <include refid="empColumns"/>
    from t_emp
    <trim prefix="where" suffixOverrides="and">
        <if test="empName != null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age != null and age != ''">
            age = #{age} and
        </if>
        <if test="gender != null and gender != ''">
            gender = #{gender}
        </if>
    </trim>
</select>

十二、MyBatis中的缓存

一共有两级缓存

默认开启一级缓存 SqlSession级别 通过同一个 SqlSession 执行的 SQL 语句会被缓存

1、一级缓存

通过同一个 sqlSession 对象查询同一个数据,会直接从缓存中获取

image-20221202014946135

image-20221202015406745

image-20221202015433182

1.1、一级缓存失效的情况

不同的 sqlSession 对象

相同的 sqlSession 对象,但是查询条件不同

相同的 sqlSession 对象,但是两次查询操作之间进行过增删改操作

相同的 sqlSession 对象,但是两次查询期间进行了手动清空缓存操作 sqlSession1.clearCache()

2、二级缓存

SqlSessionFactory 级别,多个 SqlSession 可以共享

先保存到一级缓存中,之后一级缓存关闭之后才会被保存到二级缓存中

通过同一个 sqlSessionFactory 所获取的 sqlSession 对象查询的数据会被缓存

在通过同一个 sqlSessionFactory 所获取的 sqlSession 查询相同的数据会从缓存中获取

条件:

  • 在 MyBatis 核心配置文件中设置 cacheEnabled = “true”,默认为true
  • 在映射文件中设置标签<cache/>
  • 二级缓存必须在 sqlSession 关闭或提交之后有效
  • 查询的数据所转换的实体类类型必须实现Serializable接口

2.1、二级缓存失效的情况

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

2.2、二级缓存的相关配置

image-20221203022747093

2.3、整合第三方缓存

2.3.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>

image-20221203024117559

2.3.2、添加logback.xml配置文件

注意:由于引入了logback依赖,所以log4j就失效了,我们必须要建立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="top.lukeewin.mybatis.mapper" level="DEBUG"/>
</configuration>

2.3.3、添加ehcache.xml配置文件

位置:src/resources

<?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:\Works\javalianxi\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

2.3.4、修改映射文件

需要在映射文件中的cache标签中使用type属性指定使用第三方缓存,如果没有指定,则默认使用 MyBatis 自带的二级缓存

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

3、MyBatis缓存查询的顺序

  1. 先查询二级缓存,因为二级缓存当中可能会有其他线程已经查询出来的数据。
  2. 二级缓存没有命中,则再查询一级缓存。
  3. 一级缓存也没有命中,则执行查询数据库。
  4. SqlSession 关闭之后,一级缓存当中的数据会写入到二级缓存。

十三、MyBatis逆向工程

本质:代码生成器

在pom.xml中引入插件

<!-- 控制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>

1、简单版本

src/resources下创建generatorConfig.xml配置文件

targetRuntime="MyBatis3Simple"

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版)
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"
                        userId="lukeewin"
                        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="top.lukeewin.mybatis.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="top.lukeewin.mybatis.mapper" targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="top.lukeewin.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>

双击maven中的plugins下的mybatis-generator下的mybatis-generator.generate即可生成代码。

2、复杂版本

targetRuntime="MyBatis3"

xxxByExample通过条件进行操作

xxxSelective选择性进行操作,例如insertSelective选择性进行添加,如果某个字段为null那么,不会为这个字段赋值

updateByExampleSelective根据条件选择性修改,如果某个字段为null,那么不会修改该字段的值

updateByExample根据条件进行修改,如果某个字段为null,那么会修改该字段的值为null

2.1、测试

根据主键 id 来查询

@Test
public void testMBG() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = mapper.selectByPrimaryKey(1);
    System.out.println(emp);
}

image-20221203230528937

查询所有数据

@Test
public void testMBG1() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    List<Emp> list = mapper.selectByExample(null);
    list.forEach(System.out::println);
}

image-20221203230832939

根据条件来查询特定的数据

通过XxxExample对象中的createCriteria()后的方法来指定条件

 @Test
 public void testMBG2() {
     SqlSession sqlSession = SqlSessionUtil.getSqlSession();
     EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
     EmpExample empExample = new EmpExample();
     empExample.createCriteria().andEmpNameEqualTo("高圆圆");
     List<Emp> list = mapper.selectByExample(empExample);
     list.forEach(System.out::println);
 }

要使条件之间用or连接,xxxExample调用or()方法之后,然后拼接其它条件即可

empExample.createCriteria().andEmpNameEqualTo("高圆圆").andAgeGreaterThanOrEqualTo(22);
empExample.or().andGenderEqualTo("女");

测试普通修改

@Test
public void testMBG3() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = new Emp(2, "小明", null, "男");
    mapper.updateByPrimaryKey(emp);
}

image-20221203233003065

测试选择性修改

@Test
public void testMBG4() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = new Emp(2, "小明", null, "男");
    mapper.updateByPrimaryKeySelective(emp);
}

image-20221203233209987

十四、分页

添加依赖

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

配置分页插件

在 MyBatis 核心配置文件中配置

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

测试

@Test
public void test() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 要在查询之前开启分页功能
    PageHelper.startPage(1, 4);
    List<Emp> list = mapper.selectByExample(null);
    list.forEach(System.out::println);
}

分页信息保存在 page 对象中,更多的分页信息保存在 pageInfo 中

PageInfo<>(list, 5)第一个参数为查询出来的数据,第二个参数为导航分页

@Test
public void test() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 要在查询之前开启分页功能
    Page<Object> page = PageHelper.startPage(1, 4);
    List<Emp> list = mapper.selectByExample(null);
    // 查询功能之后可以获取分页相关的所有数据
    PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
    list.forEach(System.out::println);
    System.out.println(pageInfo);

image-20221203234943141

SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp(2, "小明", null, "男");
mapper.updateByPrimaryKeySelective(emp);

}


[外链图片转存中...(img-x0bfe2QZ-1670668244118)]

# 十四、分页

添加依赖

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

配置分页插件

在 MyBatis 核心配置文件中配置

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

测试

@Test
public void test() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 要在查询之前开启分页功能
    PageHelper.startPage(1, 4);
    List<Emp> list = mapper.selectByExample(null);
    list.forEach(System.out::println);
}

分页信息保存在 page 对象中,更多的分页信息保存在 pageInfo 中

PageInfo<>(list, 5)第一个参数为查询出来的数据,第二个参数为导航分页

@Test
public void test() {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 要在查询之前开启分页功能
    Page<Object> page = PageHelper.startPage(1, 4);
    List<Emp> list = mapper.selectByExample(null);
    // 查询功能之后可以获取分页相关的所有数据
    PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
    list.forEach(System.out::println);
    System.out.println(pageInfo);

image-20221203234943141

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

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

相关文章

神仙级Python办公自动化教程(非常详细),从零基础入门到精通,轻松玩转Excel,从看这篇开始

Excel是Office办公中使用非常频繁的一个表格制作、数据分析与图表制作的组件。随着现在数据处理量越来越大&#xff0c;日常办公中很多重复性工作耗费了广大办公人员越来越多的时间&#xff0c;那么如何才能化繁为简&#xff0c;提高办公自动化水平呢&#xff1f;借助Python中的…

【小程序】小程序中插槽使用

&#x1f4ad;&#x1f4ad; ✨&#xff1a;小程序插槽   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;: 没关系 天空越黑星星越亮&#x1f49c;&#x1f49c;   &#x1f338;: 如有错误或不足之处&#xff0c;希望可以指正&#xff0c;非常感谢&#x1f60…

大学生个人网站作业 超简单DIV CSS个人网页成品 简单个人网站作业模板 HTML个人网页设计下载 简约黑白色个人主页

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

Redis大key多key拆分方案

业务场景中经常会有各种大key多key的情况&#xff0c; 比如&#xff1a; 1&#xff1a;单个简单的key存储的value很大 2&#xff1a;hash&#xff0c; set&#xff0c;zset&#xff0c;list 中存储过多的元素&#xff08;以万为单位&#xff09; 3&#xff1a;一个集群存储了…

Java脚本化编程实践整理 ScriptEngineManager万字详解

文章目录认识Java支持脚本语言的意义Java对JavaScript的支持Rhino/Nashorn概述Nashorn的目的实践操作HelloWorld执行脚本文件代码脚本语言使用Java的变量执行脚本方法/函数脚本语言使用Java的类对象脚本语言实现Java的接口脚本的多个作用域脚本语言使用Java的数据类型创建java对…

[附源码]计算机毕业设计基于Web的软考题库平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

CSS固定定位与粘性定位4大企业级案例

前面两篇文章为大家详细讲解了相对定位与绝对定位的应用场景和案例。如果想了解的可以在公众号里面查看去看。本小节我们学习下固定定位与粘性定位的应用场景和案例。 属性值 描述 relative 相对定位 相对于自身正常位置进行位置的调整 absolute 绝对定位 相对于其最近的定…

如何用实时数据分析辅助企业智能决策,这个高效的解决方案了解下?

随着产业互联网的发展&#xff0c;企业数字化能力的边界也在不断拓展&#xff0c;除了对海量数据的获取、处理及应用需求以外&#xff0c;更快地获取实时数据也开始成为大数据时代各行各业的共同目标。 在企业的业务经营中&#xff0c;实时数据是营销、运维、决策的重要支撑&am…

ChatGPT OpenAI 让学习更加高效工作中实现效率翻倍

ChatGPT是一款由OpenAI开发的聊天机器人&#xff0c;它具有出色的自然语言处理能力&#xff0c;能够与人类进行真实的对话。它的核心技术是GPT-3语言模型&#xff0c;能够自动学习语言特征&#xff0c;并进行语义理解、文本生成等任务。ChatGPT具有快速回答和丰富内容的特点&am…

Mac M1使用brew安装nvm

nvm作为node版本管理器&#xff0c;全称node version manager&#xff0c;可以管理安装的node和node-sass版本。在macOS系统上的安装步骤如下&#xff1a; *本机使用的是M1芯片&#xff0c;终端配置文件默认使用.zshrc 1. 安装homebrew /usr/bin/ruby -e "$(curl -fsSL h…

2022_SPIC_FANet

Feature aggregation network for RGBD saliency detection 1. 动机 如何将RGB和Depth充分挖掘和融合仍是一个关键问题。 第一个问题是如何从深度图中充分挖掘几何信息&#xff0c;从而可以可靠地反映场景的空间结构。 第二个问题是如何有效地融合外观信息和几何信息&…

koa项目

一.koa起步 1.项目初始化 执行 npm init -y ,生成 package.json npm init -y2.安装koa 执行命令 npm install koa3.编写基本app 创建 src/main.js //1.导入koa包 const Koa new require("Koa");//2。实例化app对象 const app new Koa();//3.编写中间件 app.…

基于C#+Mysql实现(WinForm)企业的设备管理系统【100010018】

企业的设备管理系统 1 引言 企业的设备管理在企业的生产制造和管理过程之中意义比较重大&#xff0c;明确企业的设备的产权和维护成本对于企业的成本控制和财务管理之中起到了重要的作用。随着市场竞争的加剧&#xff0c;现代企业所处的市场环境发生了深刻的变革&#xff0c;…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK13特性讲解】

JDK各个版本特性讲解-JDK13特性 一、JAVA13概述 2019年9月17日&#xff0c;国际知名的OpenJDK开源社区发布了Java编程语言环境的最新版本OpenJDK13。 Features&#xff1a;总共有5个新的JEP(JDK Enhancement Proposals): http://openjdk.java.net/projects/jdk/13/ Features: …

java基于springboot的人事管理系统-计算机毕业设计

开发环境 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven 项目介绍 在这个计…

m基于GA遗传优化的三维工程施工设施布局算法matlab仿真,显示二维和三维布局优化效果

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 GA把问题的解表示成“染色体”&#xff0c;在算法中也即是以二进制编码的串。并且&#xff0c;在执行遗传算法之前&#xff0c;给出一群“染色体”&#xff0c;也即是假设解。然后&#xff0c;把…

Matplotlib学习笔记(第二章 2.13 Matplotlib中的图形(三))

图例(Legends) legend()函数&#xff0c;使用MATLAB兼容的图例&#xff0c;放置函数自动生成图形图例。 感谢查尔斯特沃迪对图例功能的投入。 Fig. 19: Legend 文本对象的Tex表示法(TeX-notation for text objects) 下面是Matplotlib内部的mathtext工程支持的许多Tex表达式…

基于C#+SQLServer 2005实现(WinForm)校园卡消费信息系统【100010013】

校园卡消费信息管理系统 一、前言 1.1 选题说明 校园卡消费信息系统是一个实用并且与我们的学校生活密切相关的管理信息系统&#xff1b;如果能够很好的研究、开发并加以利用&#xff0c;校园卡的相关业务会变得更加简单、学生能更便利地进行消费同时准确了解自己的消费情况…

信号包络提取

目录 一、信号包络提取的相关应用&#xff1a; 二、信号包络提取方法 1、希尔伯特变换-Hilbert Transform 1.1 公式原理 1.2 例子说明 2、平方能量包络提取 3、香农能量包络提取 三、3种方法的对比 一、信号包络提取的相关应用&#xff1a; 1&#xff09;当某一个机械部…

多副本自动化发布——standalone下

一: supervisor 具体这玩意是干嘛的,我就不说了,大家自己看官网: http://www.supervisord.org/ 接下来快速部署一下。 1. pip pip是python的一个包管理器,类似于nuget,如果你的centos上没有安装,那么请执行下面命令。 1 yum -y install epel-release 2 yum -y inst…