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

Mybatis TypeHandler 介绍及使用

Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换

主要涉及到下面这几个类:

  • TypeHandler 类型转换器的顶层接口
  • BaseTypeHandler 抽象类继承自TypeHandlerMybatis中所有的类型转换器实现均继承他。
  • TypeHandlerRegistry 类型转换器注册器,负责存储类型转换器。
  • TypeAliasRegistry 类型别名转换器,用来存储类型与别名的对应关系。

TypeHandler

TypeHandler是类型转换器的顶层接口,其定义了类型转换器应该具有的功能,

TypeHandler主要解决了两个问题:

  1. 可以指定我们在Java实体类所包含的自定义类型存入数据库后的类型是什么
  2. 从数据库中取出该数据后自动转换为我们自定义的Java类型

其源码如下:

public interface TypeHandler<T> {  /** * 用于定义在Mybatis设置参数时该如何把Java类型的参数转换为对应的数据库类型 * @param ps 当前的PreparedStatement对象 * @param i 当前参数的位置 * @param parameter 当前参数的Java对象 * @param jdbcType 当前参数的数据库类型 * @throws SQLException */  void setParameter(PreparedStatement ps, int i, T parameter,  JdbcType jdbcType) throws SQLException;  /** * 用于在Mybatis获取数据结果集时如何把数据库类型转换为对应的Java类型 * @param rs 当前的结果集 * @param columnName 当前的字段名称 * @return 转换后的Java对象 * @throws SQLException */  T getResult(ResultSet rs, String columnName) throws SQLException;  /** * 用于在Mybatis通过字段位置获取字段数据时把数据库类型转换为对应的Java类型 * @param rs 当前的结果集 * @param columnIndex 当前字段的位置 * @return 转换后的Java对象 * @throws SQLException */  T getResult(ResultSet rs, int columnIndex) throws SQLException;  /** * 用于Mybatis在调用存储过程后把数据库类型的数据转换为对应的Java类型 * @param cs 当前的CallableStatement执行后的CallableStatement * @param columnIndex 当前输出参数的位置 * @return * @throws SQLException */  T getResult(CallableStatement cs, int columnIndex) throws SQLException;  }  

BaseTypeHandler

BaseTypeHandler是一个抽象类,改类实现了TypeHandler中的方法并实现了异常捕获。继承改类我们可以很容易的实现一个自定义类型转换器,其源码如下:

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {  protected Configuration configuration;  public void setConfiguration(Configuration c) {  this.configuration = c;  }  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {  if (parameter == null) {  if (jdbcType == null) {  throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");  }  try {  ps.setNull(i, jdbcType.TYPE_CODE);  } catch (SQLException e) {  throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +  "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +  "Cause: " + e, e);  }  } else {  setNonNullParameter(ps, i, parameter, jdbcType);  }  }  public T getResult(ResultSet rs, String columnName) throws SQLException {  T result = getNullableResult(rs, columnName);  if (rs.wasNull()) {  return null;  } else {  return result;  }  }  public T getResult(ResultSet rs, int columnIndex) throws SQLException {  T result = getNullableResult(rs, columnIndex);  if (rs.wasNull()) {  return null;  } else {  return result;  }  }  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {  T result = getNullableResult(cs, columnIndex);  if (cs.wasNull()) {  return null;  } else {  return result;  }  }  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;  }  

我们可以看到BaseTypeHandler对TypeHandler接口的四个方法做了一个简单的选择,把null值的情况都做了一个过滤,核心的取值和设值的方法还是抽象出来了供子类来实现。使用BaseTypeHandler还有一个好处是它继承了另外一个叫做TypeReference的抽象类,通过TypeReference的getRawType()方法可以获取到当前TypeHandler所使用泛型的原始类型。这对Mybatis在注册TypeHandler的时候是非常有好处的。在没有指定javaType的情况下,Mybatis在注册TypeHandler时可以通过它来获取当前TypeHandler所使用泛型的原始类型作为要注册的TypeHandler的javaType类型,这个在讲到Mybatis注册TypeHandler的方式时将讲到。

3 注册TypeHandler

为什么Java自带的类型在存取的时候不会出错,我们自定义的类型就会出错?那是因为mybatis已经将这些类型的TypeHandler提前写好了,并且注册好了

具体注册了哪些,我们可以看TypeHandlerRegistry这个类:

public TypeHandlerRegistry(Configuration configuration) {this.unknownTypeHandler = new UnknownTypeHandler(configuration);register(Boolean.class, new BooleanTypeHandler());register(boolean.class, new BooleanTypeHandler());register(JdbcType.BOOLEAN, new BooleanTypeHandler());register(JdbcType.BIT, new BooleanTypeHandler());register(Byte.class, new ByteTypeHandler());register(byte.class, new ByteTypeHandler());register(JdbcType.TINYINT, new ByteTypeHandler());register(Short.class, new ShortTypeHandler());register(short.class, new ShortTypeHandler());register(JdbcType.SMALLINT, new ShortTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(JdbcType.INTEGER, new IntegerTypeHandler());register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Float.class, new FloatTypeHandler());register(float.class, new FloatTypeHandler());register(JdbcType.FLOAT, new FloatTypeHandler());register(Double.class, new DoubleTypeHandler());register(double.class, new DoubleTypeHandler());register(JdbcType.DOUBLE, new DoubleTypeHandler());register(Reader.class, new ClobReaderTypeHandler());register(String.class, new StringTypeHandler());register(String.class, JdbcType.CHAR, new StringTypeHandler());register(String.class, JdbcType.CLOB, new ClobTypeHandler());register(String.class, JdbcType.VARCHAR, new StringTypeHandler());register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCLOB, new NClobTypeHandler());register(JdbcType.CHAR, new StringTypeHandler());register(JdbcType.VARCHAR, new StringTypeHandler());register(JdbcType.CLOB, new ClobTypeHandler());register(JdbcType.LONGVARCHAR, new StringTypeHandler());register(JdbcType.NVARCHAR, new NStringTypeHandler());register(JdbcType.NCHAR, new NStringTypeHandler());register(JdbcType.NCLOB, new NClobTypeHandler());register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());register(JdbcType.ARRAY, new ArrayTypeHandler());register(BigInteger.class, new BigIntegerTypeHandler());register(JdbcType.BIGINT, new LongTypeHandler());register(BigDecimal.class, new BigDecimalTypeHandler());register(JdbcType.REAL, new BigDecimalTypeHandler());register(JdbcType.DECIMAL, new BigDecimalTypeHandler());register(JdbcType.NUMERIC, new BigDecimalTypeHandler());register(InputStream.class, new BlobInputStreamTypeHandler());register(Byte[].class, new ByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());register(byte[].class, new ByteArrayTypeHandler());register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.BLOB, new BlobTypeHandler());register(Object.class, unknownTypeHandler);register(Object.class, JdbcType.OTHER, unknownTypeHandler);register(JdbcType.OTHER, unknownTypeHandler);register(Date.class, new DateTypeHandler());register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());register(JdbcType.TIMESTAMP, new DateTypeHandler());register(JdbcType.DATE, new DateOnlyTypeHandler());register(JdbcType.TIME, new TimeOnlyTypeHandler());register(java.sql.Date.class, new SqlDateTypeHandler());register(java.sql.Time.class, new SqlTimeTypeHandler());register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());register(Instant.class, new InstantTypeHandler());register(LocalDateTime.class, new LocalDateTimeTypeHandler());register(LocalDate.class, new LocalDateTypeHandler());register(LocalTime.class, new LocalTimeTypeHandler());register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());register(OffsetTime.class, new OffsetTimeTypeHandler());register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());register(Month.class, new MonthTypeHandler());register(Year.class, new YearTypeHandler());register(YearMonth.class, new YearMonthTypeHandler());register(JapaneseDate.class, new JapaneseDateTypeHandler());// issue #273register(Character.class, new CharacterTypeHandler());register(char.class, new CharacterTypeHandler());}

4. 实现自定义的TypeHandler

我们可以直接继承BaseTypeHandler来实现我们自己的类型转换器

我们要实现把json字符串转换成为我们的对象,可以这么实现:

public class JsonTypeHandler<T> extends BaseTypeHandler<T> {private final Class<T> type;public JsonTypeHandler(Class<T> type) {if (type == null) {throw new IllegalArgumentException("输入参数不能为空");}this.type = type;}@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)throws SQLException {try {String json = JsonUtil.toJson(parameter);ps.setString(i, json);} catch (Exception e) {throw new RuntimeException("Json对象转换成String失败", e);}}@Overridepublic T getNullableResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return convertJsonToObject(json);}@Overridepublic T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String json = rs.getString(columnIndex);return convertJsonToObject(json);}@Overridepublic T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String json = cs.getString(columnIndex);return convertJsonToObject(json);}private T convertJsonToObject(String json) {try {return JsonUtil.fromJson(json, type);} catch (Exception e) {throw new RuntimeException("json转换成Java对象失败", e);}}
}

因为我们使用的是Spring boot工程,只需要把JsonTypeHandler放到Spring boot可以扫描的目录下即可。

在XML中使用:

<resultMap id="BaseResultMap" type="com.db.model.SettlementBill"><id column="id" jdbcType="INTEGER" property="id" /><result column="receipts_code" jdbcType="VARCHAR" property="receiptsCode" /><result column="finance_info" jdbcType="VARCHAR"  property="financeDetailVO1" javaType="com.db.model.SettlementBill"typeHandler="com.mybatis.handler.JsonArrayTypeHandler" /></resultMap><select id="test" parameterType="java.lang.Integer" resultMap="BaseResultMap">select  id, receipts_code, finance_info from settlement_bill where id = #{id,jdbcType=INTEGER}</select>

Mybatis Plus中的使用方式:

@TableName(value = "settlement_bill", autoResultMap = true)
@Data
public class SettlementBill extends CxmBaseModel implements Serializable {@TableId(value = "id", type = IdType.AUTO)private Integer id;@TableField(value = "finance_info",typeHandler = JsonTypeHandler.class)private BatchFinanceDetailVO1 financeDetailVO1;
}

5. Mybatis自动获取TypeHandle

在介绍了Mybatis是如何注册TypeHandler之后就介绍一下Mybatis是如何获取对应的TypeHandler进行类型转换的。

如果我们在Mapper.xml文件中配置某一个属性或变量的映射关系时指定了该属性对应的javaType和jdbcType,则Mybatis会从注册好的TypeHandler中寻找对应的javaType和jdbcType组合的TypeHandler进行处理,这也是Mybatis最基本的获取TypeHandler进行类型转换的方式。

1.javaType和jdbcType都指定

假设Mybatis配置文件中有这么一段TypeHandler的注册信息:

<typeHandlers>  <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
</typeHandlers>  

看这样一个UserMapper.xml定义:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  <resultMap id="UserResult" type="User">  <id column="id" property="id"/>  <result column="interests" property="interests" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  </resultMap>  <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id">  insert into t_user(name, age, interests) values(#{name}, #{age}, #{interests, javaType=[Ljava.lang.String;, jdbcType=VARCHAR})  </insert>  <update id="updateUser" parameterType="User">  update t_user set name=#{name}, age=#{age}, interests=#{interests} where id=#{id}  </update>  <select id="findById" parameterType="int" resultMap="UserResult">  select * from t_user where id=#{id}  </select>  <delete id="deleteUser" parameterType="int">  delete from t_user where id=#{id}  </delete>  
</mapper>  

我们可以看到在id为UserResult的resultMap中,我们定义了一个对应字段interests的映射关系,并且定义了其javaType为“[Ljava.lang.String;”,jdbcType为VARCHAR,这个时候Mybatis就会到已经注册了的TypeHandler中寻找到能处理javaType和jdbcType对应的类型转换的TypeHandler来进行处理。在这里就会找到我们注册的StringArrayTypeHandler。在上面id为insertUser的insert语句中,我们也为变量interests指定了它的javaType和jdbcType属性,这时候Mybatis也会寻找javaType和jdbcType对应的TypeHandler。上面这样定义是Mybatis最基本也是最完整地获取到对应的TypeHandler的方法。

2. 只指定变量对应的javaType类型。

       这个时候Mybatis会拿着这个javaType和jdbcType为null的组合到注册的TypeHandler中寻找对应的TypeHandler。

(1)不动StringArrayTypeHandler的注册信息,把我们的UserMapper.xml改为如下形式:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  <resultMap id="UserResult" type="User">  <id column="id" property="id"/>  <result column="interests" property="interests" javaType="[Ljava.lang.String;"/>  </resultMap>  <select id="findById" parameterType="int" resultMap="UserResult">  select * from t_user where id=#{id}  </select>  
</mapper>  

此时我们发现最终执行的结果interests为null,这说明Mybatis没有使用我们定义的StringArrayTypeHandler来转换interests。

(2)UserMapper.xml还像上面那样定义,但是也只指定javaType属性来注册我们的StringArrayTypeHandler,代码如下:

<typeHandlers>  <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  </typeHandlers>  

这个时候再运行上面的测试代码,输出结果发现interests转换为User类字符串数组类型的interests属性。

     这是因为我们是以javaType和null注册的StringArrayTypeHandler,然后在需要转换interests时又是以相同的javaType和null来寻找的,所以就会找到我们注册的StringArrayTypeHandler来进行类型转换。

3. 只指定变量对应的jdbcType类型

这个时候Mybatis会利用我们指定的返回类型和对应的属性取该属性在返回类型中对应的javaType,之后再拿着该javaType和我们指定的jdbcType到注册的TypeHandler中获取对应的TypeHandler。

保持之前指定javaType和jdbcType的方式注册StringArrayTypeHandler,然后在定义interests变量的时候不指定javaType,只指定jdbcType,这个时候UserMapper.xml如下所示:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  <resultMap id="UserResult" type="User">  <id column="id" property="id"/>  <result column="interests" property="interests" jdbcType="VARCHAR"/>  </resultMap>  <select id="findById" parameterType="int" resultMap="UserResult">  select * from t_user where id=#{id}  </select>  
</mapper>  

        这个时候Mybatis是这样获取TypeHandler的:首先它发现我们的interests没有指定javaType,这个时候它就会通过我们指定的类型User和属性interests获取User类的interests属性对应的java类型,即String数组,再拿着获取到的javaType和我们指定的jdbcType即VARCHAR去寻找对应的TypeHandler,这个时候就找到了我们之前以String数组和VARCHAR注册好的StringArrayTypeHandler来处理interests的类型转换。

4. javaType类型和jdbcType类型都不指定

这个时候Mybatis会以方式2中的方式获取到对应的javaType类型,然后再以方式1获取到对应的TypeHandler。

        首先,注册一个javaType为String数组,jdbcType不指定即为null的TypeHandler—StringArrayTypeHandler,代码如下:

<?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>  <properties resource="config/jdbc.properties"></properties>  <typeAliases>  <package name="com.tiantian.mybatis.model"/>  </typeAliases>  <typeHandlers>  <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  </typeHandlers>  <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>  </environments>  <mappers>  <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  </mappers>  
</configuration>  

         然后,定义我们的interests字段的映射关系时既不指定javaType,又不指定jdbcType,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  <resultMap id="UserResult" type="User">  <id column="id" property="id"/>  <result column="interests" property="interests"/>  </resultMap>  <select id="findById" parameterType="int" resultMap="UserResult">  select * from t_user where id=#{id}  </select>  
</mapper> 

        此时我们以javaType为String数组和jdbcType为null注册了一个StringArrayTypeHandler,然后在定义interests字段的映射关系时我们没有指明其对应的javaType和jdbcType,这个时候Mybatis会利用我们指定的User类型和interests属性获取到User类的interests属性对应的java类型,即String数组,然后结合jdbcType为null去寻找注册的TypeHandler,这样就找到了StringArrayTypeHandler。经StringArrayTypeHandler的处理就把jdbcType为VARCHAR的数据转换为javaType为String数组的数据。
 

5. 直接通过变量的typeHandler属性指定其对应的TypeHandler

还有一种形式是我们直接通过变量的typeHandler属性指定其对应的TypeHandler,这个时候Mybatis就会使用该用户自己指定的TypeHandler来进行类型转换,而不再以javaType和jdbcType组合的方式获取对应的TypeHandler。

首先在Mybatis的配置文件中以javaType和jdbcType配套的方式注册一个StringArrayTypeHandler,代码如下:

<?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>  <properties resource="config/jdbc.properties"></properties>  <typeAliases>  <package name="com.tiantian.mybatis.model"/>  </typeAliases>  <typeHandlers>  <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  </typeHandlers>  <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>  </environments>  <mappers>  <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  </mappers>  
</configuration>  

按照前面说的Mybatis按照变量的javaType和jdbcType来取对应的TypeHandler的话,这里注册的StringArrayTypeHandler只有在指定变量的javaType为字符串数组而jdbcType为VARCHAR的情况下才能被获取到。

然后我们在UserMapper.xml文件中不指定interests字段对应的javaType和jdbcType,但是通过typeHandler属性指定将以StringArrayTypeHandler来进行类型转换,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  <resultMap id="UserResult" type="User">  <id column="id" property="id"/>  <result column="interests" property="interests" 
typeHandler="com.tiantian.mybatis.handler.StringArrayTypeHandler"/>  </resultMap>  <select id="findById" parameterType="int" resultMap="UserResult">  select * from t_user where id=#{id}  </select>  
</mapper>  

这是因为我们指定了进行interests字段的映射关系时使用StringArrayTypeHandler来进行类型转换。当指定了某一个字段或变量进行映射关系时所使用的TypeHandler时,Mybatis在需要进行类型转换时就使用给定的TypeHandler进行类型转换,而不会再通过javaType和jdbcType的组合去注册好的TypeHandler中寻找对应的TypeHandler。

相关文章:

Mybatis TypeHandler 介绍及使用

Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换 主要涉及到下面这几个类&#xff1a; TypeHandler 类型转换器的顶层接口BaseTypeHandler 抽象类继承自TypeHandler&#xff0c;Mybatis中所有的类型转换器实现均继承他。TypeHandlerRegistry 类型转换器注册器…...

Linux SVN 命令详解

1、将文件 checkout 到本地目录 svn checkout path&#xff08;path是服务器上的目录&#xff09; 例如&#xff1a;svn checkout svn://192.168.1.1/pro/domain 简写&#xff1a;svn co 2、往版本库中添加新的文件 svn add file 例如&#xff1a;svn add test.php(添加test.…...

Maven依赖引入的优先机制

xxxx待持续更新...

全开源无加密跨境电商购物网站系统源码(无货源模式+多语言+多货币)

在全球化的时代背景下&#xff0c;跨境电商成为了越来越受欢迎的消费方式&#xff0c;而建立一个源码无加密多语言跨境购物网站系统是一个具有挑战性的任务&#xff0c;但完全可行。以下是这个过程的一些主要步骤&#xff1a; 1. 确定需求和功能规划&#xff1a;先确定网站需要…...

Python常用视频编辑操作——读取与保存视频、更改帧数、拼接视频、视频语音合并、视频与图像互转等

1.更改视频帧数 降低视频帧数&#xff0c;简单的操作只能降低视频帧数&#xff0c;如果要增加视频帧数&#xff0c;那就要使用深度学习进行插帧处理&#xff1a; import cv2 from moviepy.editor import * def change_fps(inpt_path,output_path,fps):# 加载视频video Video…...

从javascript到vue再到react的演变

当提到前端开发中的框架时&#xff0c;JavaScript、Vue.js和React.js是三个最常见的名词。它们代表了Web开发中不同的技术选择和演变过程。本文将探讨JavaScript从原生到Vue.js再到React.js的演变&#xff0c;以及每个阶段的特点和优势。 JavaScript: 动态语言的基础 JavaScr…...

50个渗透(黑客)常用名词及解释

目录 前言一、渗透测试1. 渗透测试&#xff1a;2. 黑盒测试&#xff1a;3. 白盒测试&#xff1a;4. 社会工程学&#xff1a;5. 缓冲区溢出&#xff1a;6. 拒绝服务攻击&#xff1a;7. DDoS攻击&#xff1a;8. XSS攻击&#xff1a;9. CSRF攻击&#xff1a;10. SQL注入&#xff1…...

开源游戏引擎和模拟器的项目合集 | 开源专题 No.38

yuzu-emu/yuzu Stars: 26.2k License: GPL-3.0 yuzu是一款全球最受欢迎的开源Nintendo Switch模拟器&#xff0c;由Citra创建者编写。它采用C语言编写&#xff0c;并具有可移植性&#xff0c;在Windows和Linux上进行积极维护。该模拟器能够全速运行大多数商业游戏&#xff0c…...

ELK + Filebeat 分布式日志管理平台部署

ELK Filebeat 分布式日志管理平台部署 1、前言1.1日志分析的作用1.2需要收集的日志1.3完整日志系统的基本特征 2、ELK概述2.1ELK简介2.2为什么要用ELK?2.3ELK的组件 3、ELK组件详解3.1Logstash3.1.1简介3.1.2Logstash命令常用选项3.1.3Logstash 的输入和输出流3.1.4Logstash配…...

Stable Diffusion原理

一、Diffusion扩散理论 1.1、 Diffusion Model&#xff08;扩散模型&#xff09; Diffusion扩散模型分为两个阶段&#xff1a;前向过程 反向过程 前向过程&#xff1a;不断往输入图片中添加高斯噪声来破坏图像反向过程&#xff1a;使用一系列马尔可夫链逐步将噪声还原为原始…...

2022年亚太杯APMCM数学建模大赛A题结晶器熔剂熔融结晶过程序列图像特征提取及建模分析求解全过程文档及程序

2022年亚太杯APMCM数学建模大赛 A题 结晶器熔剂熔融结晶过程序列图像特征提取及建模分析 原题再现&#xff1a; 连铸过程中的保护渣使钢水弯液面隔热&#xff0c;防止钢水在连铸过程中再次氧化&#xff0c;控制传热&#xff0c;为铸坯提供润滑&#xff0c;并吸收非金属夹杂物…...

金融网站如何做好安全防护措施?

联网的发展为当代很多行业的发展提供了一个更为广阔的平台&#xff0c;而对于中国的金融业来说&#xff0c;互联网金融这一新兴理念已经为 人们所接受&#xff0c;且发展迅速。我们也都知道金融行业对互联网技术是非常严格的&#xff0c;这对互联网的稳定性和可靠性提出了较高的…...

2023年中国恋爱社区未来发展趋势分析:多元化盈利模式实现可持续发展[图]

恋爱社区指满足情侣之间互动、记录及娱乐需求&#xff0c;以维护情侣恋爱关系的虚拟社区。恋爱社区行业主要以线上APP的虚拟形式为用户提供相关服务&#xff0c;其业务包括情侣记录、情侣互动、情侣娱乐、公共社区、线上购物、增值服务。 恋爱社区主要业务 资料来源&#xff1…...

Elasticsearch:生成式人工智能带来的社会转变

作者&#xff1a;JEFF VESTAL 了解 Elastic 如何走在大型语言模型革命的最前沿 – 通过提供实时信息并将 LLM 集成到数据分析的搜索、可观察性和安全系统中&#xff0c;帮助用户将 LLM 提升到新的高度。 iPhone 社会转变&#xff1a;新时代的黎明 曾几何时&#xff0c;不久前…...

服务器数据恢复-RAID5中磁盘被踢导致阵列崩溃的服务器数据恢复案例

服务器数据恢复环境&#xff1a; 一台3U的某品牌机架式服务器&#xff0c;Windows server操作系统&#xff0c;100块SAS硬盘组建RAID5阵列。 服务器故障&#xff1a; 服务器有一块硬盘盘的指示灯亮黄灯&#xff0c;这块盘被raid卡踢出后&#xff0c;raid阵列崩溃。 服务器数据…...

负荷不均衡问题分析处理流程

一、负荷不均衡分析 负荷不均衡判断标准&#xff1a;4G同覆盖扇区内存在无线利用率大于50%的小区&#xff0c;且两两小区间无线利用率差值大于30%&#xff0c;判定为4G负荷不均衡扇区&#xff1b;5G同覆盖扇区内存在无线利用率大于50%的小区&#xff0c;且两两小区间无线利用率…...

Spring篇---第四篇

系列文章目录 文章目录 系列文章目录一、说说你对Spring的IOC是怎么理解的?二、解释一下spring bean的生命周期三、解释Spring支持的几种bean的作用域?一、说说你对Spring的IOC是怎么理解的? (1)IOC就是控制反转,是指创建对象的控制权的转移。以前创建对象的主动权和时机…...

算法通过村第十五关-超大规模|白银笔记|经典问题

文章目录 前言从40个亿中产生一个不存在的整数位图存储数据的原理使用10MB来存储如何确定分块的区间 用2GB内存在20亿的整数中找到出现次数最多的数从100亿个URL中查找的问题40亿个非负整数中找出两次的数。总结 前言 提示&#xff1a;人生之中总有空白&#xff0c;但有时&…...

Mini小主机All-in-one搭建教程6-安装苹果MacOS系统

笔者使用的ESXI7.0 Update 3 抱着试试的态度想安装一下苹果的MacOS系统 主要步骤有2个 1.解锁unlocker虚拟机系统 2.安装苹果MacOS系统 需要下载的文件 unlocker 这一步是最耗时间的&#xff0c;要找到匹配自己系统的unlocker文件。 https://github.com/THDCOM/ESXiUnloc…...

Android中使用Glide加载圆形图像或给图片设置指定圆角

一、Glide加载圆形头像 效果 R.mipmap.head_icon是默认圆形头像 ImageView mImage findViewById(R.id.image);RequestOptions options new RequestOptions().placeholder(R.mipmap.head_icon).circleCropTransform(); Glide.with(this).load("图像Uri").apply(o…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...