Mybatis简介(二)

news2024/12/26 13:48:25

1、多表映射

简介一 链接

对于数据库的操作,很多时候我们都是在多表的基础上进行操作的,在这里讲一下多表属性值与列名映射。

案例:这里有一个订单表和一个客户表

CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) );

CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); 

INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');

INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 

1.1对一关系

我们的要求是根据订单id返回该订单信息与客户信息。这是一对一的关系。

对于多表映射,我们先写出实体类,先不考虑对应关系。之后再根据需求在实体类中添加信息。

对于对一关系,我们只要在实体类中添加一个对应实体类的属性即可。

订单类:

package com.cky.pojo;

import lombok.Data;

@Data
public class Order {
    private Integer orderId;
    private String orderName;
    private Integer customerId;
    //查询订单以及订单对应的客户信息 对一的关系
    private Customer customer;
}

订单mapper接口:

package com.cky.mapper;


import com.cky.pojo.Order;

//查询订单以及订单对应的客户信息 对一的关系
public interface OrderMapper {
   Order querybyId(Integer id);
}

订单mapperxml编写

<?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.cky.mapper.OrderMapper">
    <resultMap id="ordermap" type="order">
        <id property="orderId" column="order_id"></id>
        <result property="orderName" column="order_name"></result>
        <result property="customerId" column="customer_id"></result>
        <association property="customer" javaType="customer">
          <id column="customer_id" property="customerId"></id>
            <result column="customer_name" property="customerName"></result>
        </association>
    </resultMap>
    <select id="querybyId" resultMap="ordermap">
        SELECT order_id,order_name,c.customer_id,customer_name
        FROM t_order o
        LEFT JOIN t_customer c
        ON o.customer_id=c.customer_id
        WHERE o.order_id=#{orderId}
    </select>


</mapper>

对应关系可以参考如下图:

注意:对于单个属性,我们使用association即可,但于多个属性,我们采用collection 

mybatis-config.xml配置编写

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!-- 使用settings对Mybatis全局进行设置 -->
            <!-- 将xxx_xxx这样的列名自动映射到xxXxx这样驼峰式命名的属性名 -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!--开启resultMap自动映射 -->
        <setting name="autoMappingBehavior" value="FULL"/>

    </settings>
    <!--给该包的类起别名,第一个字母小写-->
    <typeAliases>
        <package name="com.cky.pojo"/>
    </typeAliases>
    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">
            <!-- Mybatis的内置的事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="cky"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/OrderMapper.xml"/>
        <mapper resource="mappers/CustomerMapper.xml"/>
    </mappers>

</configuration>

测试类:

public class Mytest {
    private SqlSession sqlSession;
    @BeforeEach
    public void before() throws IOException {
        sqlSession=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession(true);
    }
    @AfterEach
    public void after(){
        sqlSession.close();
    }
    @Test
    public void test_01(){
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        Order order = orderMapper.querybyId(1);
        System.out.println(order);
        System.out.println(order.getCustomer());

    }}

1.2 对多关系

对于1对多的关系,我们只需要在对应的类中添加对多类的属性即可,是一个list集合

比如 我们需要根据客户id返回客户信息以及客户对应的订单信息

则我们在客户类中添加上 订单类的list属性即可

客户类

package com.cky.pojo;

import lombok.Data;

import java.util.List;

@Data
//对多,查询一个客户信息以及客户对应的订单信息
public class Customer {
    private Integer customerId;
    private String customerName;
    private List<Order> orderList;
}

客户mapper接口

package com.cky.mapper;

import com.cky.pojo.Customer;

public interface CustomerMapper {
    Customer querycustomerWithOrder(Integer id);
}

客户mapperxml

<?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.cky.mapper.CustomerMapper">
    <resultMap id="customermap" type="customer">
        <id property="customerId" column="customer_id"></id>
        <collection ofType="order" property="orderList">
            <id property="orderId" column="order_id"></id>
        </collection>
    </resultMap>
    <select id="querycustomerWithOrder" resultMap="customermap">
        SELECT order_id,order_name,c.customer_id,customer_name
        FROM t_order o
        LEFT JOIN t_customer c
        ON o.customer_id=c.customer_id
        WHERE c.customer_id=#{customerId}
    </select>


</mapper>

 对应关系

配置xml文件与上边相同

在这里需要注意

1.2.1 多表映射优化

对于对一关系,我们的映射关系resultMap中,不仅写了id还需要写result,但是我们可以开始自动映射,只要我们的关系属性名与列名相同,或者我们开启了驼峰式映射,就可以进行自动的result映射。 比如对多的客户mapperxml文件中resultMap的编写,我们就只写了id。没有写普通列的映射关系。

<!--开启resultMap自动映射 -->
<setting name="autoMappingBehavior" value="FULL"/>

对于resultMap中的id属性我们还是需要添上的。

1.3 多表映射总结

resultType只能进行单表映射,所以对于多表映射,我们需要resulMap属性来编写对应的映射关系。

 2、动态查询

在现实生活中,我们经常遇到多条件查询的情况。对于多条件查询,就免不了一些属性不取值的情况,那这种动态语句的sql要如何写呢?Mybatis提供了很多标签,大大简化了原始JDBC语句拼接的情况。

2.1 if和where

<!--
  List<Employee> selectEmployeeByCondition(Employee employee);
if 可以用来进行判断 如果test里边的返回true,则该语句执行
where 的作用 1.如果where 中有一句语句执行,则添加上where。防止 都不执行 多出一个where
            2、去掉多余的and 或者 or
        比如  <if test="empName !=null">
                emp_name=#{empName}
            </if>
            不执行
             and emp_salary=#{empSalary} 执行
             就会导致多一个 and
 test中取key :可以访问实体类的属性,但不能访问数据库的字段。
-->
    <select id="selectEmployeeByCondition" resultType="employee">
        select * from t_emp
        <where>
            <if test="empName !=null">
                emp_name=#{empName}
            </if>
            <if test="empSalary !=nul">
               and emp_salary=#{empSalary}
            </if>
        </where>
    </select>

2.2、set标签

<!--int updateEmployeeDynamic(Employee employee);
     update t_tmp set emp_name=#{empName},emp_salary=#{empSalary}
    where emp_id=#{empId}
     我们需要让 姓名不为空 并且 薪资大于3000 更新
    set的作用:1、防止右边语句都不执行,多出一个set,set标签会自动判断需不需要添加set
              2、去掉多余的逗号
      set 标签也可以和if标签同时使用
-->
<update id="updateEmployeeDynamic">
    update t_tmp 
    <set>
        <if test="empName!=null">
            emp_name=#{empName},
        </if>
        <if test="empSalary and empSalary &gt; 3000">
            emp_salary=#{empSalary}
        </if>
    </set>
    where emp_id=#{empId}
</update>

2.3 trim标签

使用trim标签控制条件部分两端是否包含某些字符

- prefix属性:指定要动态添加的前缀
- suffix属性:指定要动态添加的后缀
- prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
- suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值

比如使用trim来代替set

<update id="updateEmployeeDynamic">
    update t_tmp
    <trim prefix="set" suffixOverrides=",">
        <if test="empName!=null">
            emp_name=#{empName},
        </if>
        <if test="empSalary and empSalary &gt; 3000">
            emp_salary=#{empSalary}
        </if>
    </trim>
    where emp_id=#{empId}
</update>

2.4 choose/when/otherwise标签

在多个分支条件中,仅执行一个。

- 从上到下依次执行条件判断
- 遇到的第一个满足条件的分支会被采纳
- 被采纳分支后面的分支都将不被考虑
- 如果所有的when分支都不满足,那么就执行otherwise分支

<!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
    select emp_id,emp_name,emp_salary from t_emp
    where
    <choose>
        <when test="empName != null">emp_name=#{empName}</when>
        <when test="empSalary &lt; 3000">emp_salary &lt; 3000</when>
        <otherwise>1=1</otherwise>
    </choose>
    
    <!--
     第一种情况:第一个when满足条件 where emp_name=?
     第二种情况:第二个when满足条件 where emp_salary < 3000
     第三种情况:两个when都不满足 where 1=1 执行了otherwise
     -->
</select>

2.5 foreach 标签

可以用来进行批量操作

比如根据id批量查询 

<!--
    List<Employee> queryBatch(@Param("ids") List<Integer> ids);
   select * from t_emp where emp_id in(1,2,3)
-->

<select id="queryBatch" resultType="employee">

    select * from t_emp where emp_id in
    <!--
    collection 是我们要遍历的 集合
    open 遍历之前要添加的字符串
    close 遍历之后要添加的字符串
    separator 分隔符
    item 遍历的每一个集合项
    -->
    <foreach collection="ids" open="(" separator="," close=")" item="id">
   //遍历的内容 #{遍历的key}
         #{id}
    </foreach>

</select>

根据id 批量删除

<!--
 int deleteBatch(@Param("ids") List<Integer> ids);
 delete from t_emp where emp_id in (1,2,3)
-->
<delete id="deleteBatch">
    delete from t_emp where emp_id in 
    <foreach collection="ids" open="(" separator="," close=")" item="id">
        #{id}
    </foreach>
</delete>

批量插入

<!--
    int insertBatch(@Param("list") List<Employee> employeeslist);
       insert into t_emp(emp_name,emp_salary) values("".""),("","")
    -->
<insert id="insertBatch">
    insert into t_emp(emp_name,emp_salary) values
    <foreach collection="list" separator="," item="emp">
        (#{emp.empName},#{emp.empSalary})
    </foreach>
</insert>

批量更新

上面批量插入的例子本质上是一条SQL语句,而实现批量更新则需要多条SQL语句拼起来,用分号分开。也就是一次性发送多条SQL语句让数据库执行。此时需要在数据库连接信息的URL地址中设置:

<property name="url" value="jdbc:mysql://localhost:3306/
mybatis?allowMultiQueries=true"/>

<!--
   int updateBatch(@Param("list") List<Employee> employeeslist);
   更新的话比较特殊
   实则是多条sql语句一起,上边的删除查询等其实是一条sql语句
-->
<update id="updateBatch">
    <foreach collection="list" item="emp">
        update t_emp set emp_name=#{emp.empName},emp_salary=#{emp.empSalary}
        where emp_id=#{emp.empId}
    </foreach>

</update>

在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@Param注解明确声明变量的名称,然后在foreach标签的collection属性中按照@Param注解指定的名称来引用传入的参数。 

比如:

public interface EmployeeMapper {
    List<Employee> queryBatch(@Param("ids") List<Integer> ids);
    int deleteBatch(@Param("ids") List<Integer> ids);
    int updateBatch(@Param("list") List<Employee> employeeslist);
    int insertBatch(@Param("list") List<Employee> employeeslist);

}

 2.6 sql 标签

抽取重复的SQL片段

<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="mySelectSql">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>

引用已抽取的SQL片段 

<!-- 使用include标签引用声明的SQL片段 -->

<select id="" class="">
<include refid="mySelectSql"/>

where emp_id=#{empId}

</select> 

3、Mybatis高级拓展

3.1 mapper按包批量扫描

1. 需求

    Mapper 接口配置文件很多时,在全局配置文件中一个一个注册太麻烦,希望有一个办法能够一劳永逸。

2 配置方式

    Mybatis 允许在指定 Mapper 映射文件时,只指定其所在的包:

<mappers>
    <package name="com.cky.mapper"/>
</mappers>

    此时这个包下的所有 Mapper 配置文件将被自动加载、注册,比较方便。

3、配置要求

- Mapper 接口和 Mapper 配置文件名称一致
    - Mapper 接口:EmployeeMapper.java
    - Mapper 配置文件:EmployeeMapper.xml

-要求打包后mapper接口和mapper接口的配置文件在同一个文件夹下

  这就需要我们

  ①可以将mapperxml文件放在mapper接口所在的包![不推荐]

 ② 可以在resources下创建mapper接口包一致的文件夹结构存放mapperxml文件[推荐]

在resources 下创建包 分级的话 要用/ 因为是文件 在resurces下如果使用.的话,仍然是同一级目录。

而在java中 用. 因为创建的是包 要注意

3.2 插件机制和分页插件使用

3.2.1插件机制

MyBatis 对插件进行了标准化的设计,并提供了一套可扩展的插件机制。插件可以在用于语句执行过程中进行拦截,并允许通过自定义处理程序来拦截和修改 SQL 语句、映射语句的结果等。

具体来说,MyBatis 的插件机制包括以下三个组件:

1. `Interceptor`(拦截器):定义一个拦截方法 `intercept`,该方法在执行 SQL 语句、执行查询、查询结果的映射时会被调用。
2. `Invocation`(调用):实际上是对被拦截的方法的封装,封装了 `Object target`、`Method method` 和 `Object[] args` 这三个字段。
3. `InterceptorChain`(拦截器链):对所有的拦截器进行管理,包括将所有的 Interceptor 链接成一条链,并在执行 SQL 语句时按顺序调用。

插件的开发非常简单,只需要实现 Interceptor 接口,并使用注解 `@Intercepts` 来标注需要拦截的对象和方法,然后在 MyBatis 的配置文件中添加插件即可。

PageHelper 是 MyBatis 中比较著名的分页插件,它提供了多种分页方式(例如 MySQL 和 Oracle 分页方式),支持多种数据库,并且使用非常简单。下面就介绍一下 PageHelper 的使用方式。

3.2.2分页插件 PageHelper的使用

1、首先 我们需要在pom.xml 导入外部依赖

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

2、Mybatis-config.xml 中配置分页插件

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>
 

其中,com.github.pagehelper.PageInterceptor 是 PageHelper 插件的名称,dialect 属性用于指定数据库类型(支持多种数据库)

3、分页插件的使用

@Test
public void testTeacherRelationshipToMulti() {

    TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);

    PageHelper.startPage(1,2);
    // 查询Customer对象同时将关联的Order集合查询出来
    List<Teacher> allTeachers = teacherMapper.findAllTeachers();
//注意:在分页配置区我们只能写一句查询语句。
    PageInfo<Teacher> pageInfo = new PageInfo<>(allTeachers);

将其封装成一个pageinfo实体类对象,我们可以获取很多信息(比如一共多少页,一共多少条信息,当前多少页,是否有下一页等)。

    System.out.println("pageInfo = " + pageInfo);
    long total = pageInfo.getTotal(); // 获取总记录数
    System.out.println("total = " + total);
    int pages = pageInfo.getPages();  // 获取总页数
    System.out.println("pages = " + pages);
    int pageNum = pageInfo.getPageNum(); // 获取当前页码
    System.out.println("pageNum = " + pageNum);
    int pageSize = pageInfo.getPageSize(); // 获取每页显示记录数
    System.out.println("pageSize = " + pageSize);
    List<Teacher> teachers = pageInfo.getList(); //获取查询页的数据集合
    System.out.println("teachers = " + teachers);
    teachers.forEach(System.out::println);

}

 

3.3 orm介绍和逆向工程

3.3.1 Orm介绍

ORM(Object-Relational Mapping,对象-关系映射)是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射,最后我们就可以通过方法调用进行数据库操作!!

最终: **让我们可以使用面向对象思维进行数据库操作!!!**

**ORM 框架通常有半自动和全自动两种方式。**

- 半自动 ORM 通常需要程序员手动编写 SQL 语句或者配置文件,将实体类和数据表进行映射,还需要手动将查询的结果集转换成实体对象。
- 全自动 ORM 则是将实体类和数据表进行自动映射,使用 API 进行数据库操作时,ORM 框架会自动执行 SQL 语句并将查询结果转换成实体对象,程序员无需再手动编写 SQL 语句和转换代码。

**下面是半自动和全自动 ORM 框架的区别:**

1. 映射方式:半自动 ORM 框架需要程序员手动指定实体类和数据表之间的映射关系,通常使用 XML 文件或注解方式来指定;全自动 ORM 框架则可以自动进行实体类和数据表的映射,无需手动干预。
2. 查询方式:半自动 ORM 框架通常需要程序员手动编写 SQL 语句并将查询结果集转换成实体对象;全自动 ORM 框架可以自动组装 SQL 语句、执行查询操作,并将查询结果转换成实体对象。
3. 性能:由于半自动 ORM 框架需要手动编写 SQL 语句,因此程序员必须对 SQL 语句和数据库的底层知识有一定的了解,才能编写高效的 SQL 语句;而全自动 ORM 框架通过自动优化生成的 SQL 语句来提高性能,程序员无需进行优化。
4. 学习成本:半自动 ORM 框架需要程序员手动编写 SQL 语句和映射配置,要求程序员具备较高的数据库和 SQL 知识;全自动 ORM 框架可以自动生成 SQL 语句和映射配置,程序员无需了解过多的数据库和 SQL 知识。

常见的半自动 ORM 框架包括 MyBatis 等;常见的全自动 ORM 框架包括 Hibernate、Spring Data JPA、MyBatis-Plus 等。

3.3.2 逆向工程

    MyBatis 的逆向工程是一种自动化生成持久层代码和映射文件的工具,它可以根据数据库表结构和设置的参数生成对应的实体类、Mapper.xml 文件、Mapper 接口等代码文件,简化了开发者手动生成的过程。逆向工程使开发者可以快速地构建起 DAO 层,并快速上手进行业务开发。
   MyBatis 的逆向工程有两种方式:通过 MyBatis Generator 插件实现和通过 Maven 插件实现。无论是哪种方式,逆向工程一般需要指定一些配置参数,例如数据库连接 URL、用户名、密码、要生成的表名、生成的文件路径等等。
   总的来说,MyBatis 的逆向工程为程序员提供了一种方便快捷的方式,能够快速地生成持久层代码和映射文件,是半自动 ORM 思维像全自动发展的过程,提高程序员的开发效率。

**注意:逆向工程只能生成单表crud的操作,多表查询依然需要我们自己编写!**

3.3.3 逆向工程插件MybatisX的使用

a.下载MybatisX插件

b.连接我们的数据库

c.逆向工程使用

查看生成结果:

4、Mybatis总结

 

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

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

相关文章

在 Elasticsearch 中丰富你的 Elasticsearch 文档

作者&#xff1a;David Pilato 对于 Elasticsearch&#xff0c;我们知道联接应该在 “索引时” 而不是查询时完成。 本博文是一系列三篇博文的开始&#xff0c;因为我们可以在 Elastic 生态系统中采取多种方法。 我们将介绍如何在 Elasticsearch 中做到这一点。 下一篇博文将介…

node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)

文章目录 ⭐前言⭐ 环境准备⭐ 实现过程⭐ mysql 配置⭐路由前的准备⭐账号注册生成token⭐账号登录生成token⭐token登录 ⭐ 自测过程截图⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于node实战——后端koa项目配置jwt实现登录注册&#xff08;n…

1230. K倍区间(前缀和)

题目&#xff1a; 1230. K倍区间 - AcWing题库 突破口&#xff1a; 区间遍历枚举一般先枚举右端点&#xff0c;再枚举左端点&#xff0c;注意由右端点限制左端点 思路&#xff1a;1.暴力 #include<cstdio> #include<iostream> #include<algorithm> #incl…

Win 7 VPN拨号错误734.

正在验证用户名和密码错误 734: PPP 链接控制协议终止。 如果您继续收到错误信息&#xff0c;您可以启用日志记录来做分析。 其他电脑拨号都成功.就这个电脑不行.找了很久,修改之后报好成功 ************************** 找到是跟下面两个两个注册表信息有关,尤其是第一个我…

基于Pytest+Requests+Allure实现接口自动化测试!

一、整体结构 框架组成&#xff1a;pytestrequestsallure设计模式&#xff1a; 关键字驱动项目结构&#xff1a; 工具层&#xff1a;api_keyword/参数层&#xff1a;params/用例层&#xff1a;case/数据驱动&#xff1a;data_driver/数据层&#xff1a;data/逻辑层&#xff1a…

75 寻找旋转排序数组中的最小值

寻找旋转排序数组中的最小值 题解1 一次循环(正确理解题意)题解2 二分 已知一个长度为 n 的数组&#xff0c;预先按照 升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到&#xff1a; …

刚刚:2023阿里云双十一优惠活动上线了!

2023阿里云双十一优惠活动「金秋云创季」开始啦&#xff0c;10月27日到10月31日可以领满减优惠&#xff0c;到11月1日和11月11日之间可以购买云服务器等产品&#xff0c;11.12到11.30日赢最高百万上云抵扣金&#xff0c;阿里云百科aliyunbaike.com分享2023阿里云双十一优惠活动…

Xray的简单使用

xray 简介 xray 是一款功能强大的安全评估工具&#xff0c;由多名经验丰富的一线安全从业者呕心打造而成&#xff0c;主要特性有: 检测速度快。发包速度快; 漏洞检测算法效率高。支持范围广。大至 OWASP Top 10 通用漏洞检测&#xff0c;小至各种 CMS 框架 POC&#xff0c;均…

前端实现打印功能Print.js

前端实现打印的方式有很多种&#xff0c;本人恰好经历了几个项目都涉及到了前端打印&#xff0c;目前较为推荐Print.js来实现前端打印 话不多说&#xff0c;直接上教程 官方链接: Print.js官网 在项目中如何下载Print.js 使用npm下载&#xff1a;npm install print-js --sav…

python 从mssql取出datetime2类型之后格式化

我mssql是datetime2类型&#xff0c;用df取出之后发现是个纳秒的int&#xff08;1698419713000000000 这种&#xff09; 所以格式化的话就需要变成秒为单位&#xff0c;他们之间是10的9次方倍。所以先除以1e9之后用datetime.datetime.fromtimestamp()转换之后再format就行了 l…

CCF CSP认证历年题目自练 Day39

题目 试题编号&#xff1a; 201312-5 试题名称&#xff1a; I’m stuck! 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   给定一个R行C列的地图&#xff0c;地图的每一个方格可能是’#‘, ‘’, ‘-’, ‘|’, ‘.’, ‘S’, ‘…

系列十九、循环依赖(一)

一、概述 循环依赖是指&#xff0c;多个bean之间相互依赖&#xff0c;形成了一个闭环。比如A依赖于B、B依赖于C、C依赖于A&#xff0c;形成了一个圈。 二、两种方式对循环依赖的影响 2.1、官网说明 2.2、结论 我们AB循环依赖问题只要A的注入方式是setter、并且是singleton&am…

Android14 WMS启动流程

一 概述 本文Android14源代码可参考&#xff1a;Search 在 Android 系统中&#xff0c;从设计的角度来看&#xff0c;窗口管理系统是基于 C/S 模式的。整个窗口系统分为服务端和客户端两大部分&#xff0c;客户端负责请求创建窗口和使用窗口&#xff0c;服务端完成窗口的维护…

智慧工地管理系统源码-数字孪生智慧工地可视化解决方案

一、智慧工地建设背景 我国经济发展正从传统粗放式的高速增长阶段&#xff0c;进入高效率、低成本、可持续的中高速增长阶段。随着现代建筑的复杂度和体量等不断增加&#xff0c;施工现场管理的内容越来越多&#xff0c;管理的技术难度和要求在不断提高。传统的施工现场管理模…

用超声波清洗机洗眼镜的有哪些?清洁力强的超声波清洗机不能错过

超声波清洗机在清洗眼镜方面表现出色&#xff0c;其强大的清洁能力可以彻底清除眼镜上的污垢和细菌。这种清洗方式被认为是一种高效且卫生的清洁方式&#xff0c;因为它利用高频振动和微射流打击力来清除污垢和细菌&#xff0c;而不是使用化学物质。对于那些长时间佩戴眼镜或者…

windows + ubuntu + vscode开发环境配置安装

一、卸载WSL/WSL2 如果安装了windows子系统的朋友&#xff0c;可以选择继续使用。或者提前卸载WSL&#xff0c;再选择安装虚拟机。虚拟机占用内存较大&#xff0c;WSL可能对于开发的一些需求还有欠缺。根据自己的实际情况进行选择。 WIN10/11安装WSL(请参考官方资料&#xff0c…

TSINGSEE青犀智慧仓储可视化视频智能监管系统方案

一、背景与需求 对于现在很多大型工厂或者物流基地来说&#xff0c;仓库无疑是存放物品的重点场所。仓储存放着大量货物&#xff0c;同时存在大量的辅助设备&#xff0c;需要进行全方位的监管&#xff0c;以避免发生安全事故&#xff0c;造成财产损失。原有的人工巡检方式已无…

Ubuntu安装AdGuardhome(树莓派安装AdGuardhome)

Ubuntu安装AdGuardhome&树莓派安装AdGuardhome 1.什么是AdGuardhome2.设备情况3.3.1.下载AdGuardhome3.2.解压3.3.安装3.4.仪表盘配置3.5.dns黑名单添加3.6.DNS白名单设置3.7常规设置3.8. dns设置3.9.加密设置 4.客户端设置 1.什么是AdGuardhome AdGuard Home 是网络范围的…

传奇服务器配置如何搭建

传奇服务器在中国页游发展中作为一个经典制作吸引了很多玩家的喜欢&#xff0c;很多人也想搭建一个属于自己团队的传奇游戏服务器&#xff0c;今天就让小编来讲一讲该如何搭建吧&#xff01; 首先是硬件配置&#xff0c;传奇游戏的服务器需要较高的硬件配置&#xff0c;选择双路…

Kubernetes数据卷Volume和数据卷分类(emptyDir、nfs、hostPath、ConfigMap)详解

Kubernetes数据卷Volume和数据卷分类详解 数据卷概述 Kubernetes Volume&#xff08;数据卷&#xff09;主要解决了如下两方面问题&#xff1a; 数据持久性&#xff1a;通常情况下&#xff0c;容器运行起来之后&#xff0c;写入到其文件系统的文件暂时性的。当容器崩溃后&am…