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

SSM框架学习——SqlSession以及Spring与MyBatis整合

SqlSession以及Spring与MyBatis整合

准备所需要的JAR包

要实现MyBatis与Spring的整合,很明显需要这两个框架的JAR包,但是只是使用这两个框架中所提供的JAR包是不够的,还需要配合其他包使用:

  • Spring的JAR包
  • MyBatis的JAR包
  • Spring与MyBatis整合中间包mybatis-spring-x.x.x.jar
  • 数据库驱动JAR(以MYSQL为例)mysql-connector-java-x.x.x-bin.jar
  • 数据源所需的JAR(DBCP)commons-dbcp2-x.x.x.jarcommons-pool2-x.x.x.jar

配置文件介绍

关于resources文件夹

我们在之前的项目中,几乎每次都会创建这个文件夹,然后Use as a source folder,那么这个文件夹到底是用来干啥的,凭什么使用它里面的文件是直接写文件名?

实际上这个文件夹是专门存放你的应用所需资源的,如XML等配置文件。这个文件夹被标记为source folder后,在编译后,里面的文件会放到与编译好的文件相同目录里,所以你读取的直接使用文件名实际上是相对路径。

pom.xml

如果我们创建的是一个Maven项目,就可以在pom.xml里添加<properties></properties>标签来定义库版本,然后在下方的<dependencies></dependencies>中的<dependency></dependency><version></version>${...}形式引用它。

下面的XML文件省略了很多,仅为了演示。

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><junit.version>4.12</junit.version><!-- 此处表示省略 -->[...]
</properties><dependencies><!-- JUINT --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><!-- 引用上方标签的版本号 --><version>${junit.version}</version><scope>test</scope></dependency><!-- 此处表示省略 -->[...]
</dependencies>

db.properties

db.properties主要包含一些数据库连接信息,比如JDBC连接驱动、数据库账户名和密码等。

我们在之前的项目中就已经使用过这个文件了,但我们一直没有详细介绍过其每条内容的含义(实际上语义很明显)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=db_mybatis
jdbc.password=db_mybatis

首先第一行jdbc.driver是指定数据库连接驱动。JDBC即Java数据库连接,它定义了一套关系型数据库的规则,没错实际上就是接口,然后实现并不是由Java官方进行的,而是交给各个数据库厂商来做,它们打包的库也就是JAR包,就被叫做数据库驱动,同时也意味着不同数据库就有不同的驱动实现。

程序设计者无需去关心每个数据库驱动是怎么实现的,而是像你把手机充电器插到墙上的插座一样,把驱动按照接口给“插”进去。这就是面向接口编程的好处。

你的程序只是一个调用者,数据库驱动就像一个代理人,你要先告诉这个代理人怎么操作,然后让这个代理人去真正操纵数据库(怎么操纵你是不关心的,只要满足你的操作需求即可)。你与这个代理人约定的通用交流方式就是刚才的接口,而代理人具体的操纵方式就是驱动的实现。

我们所给的代码中很显然是MySQL的数据库驱动,后面的mysql.jdbc.Driver实际上是随你pom.xml添加的包一块引入的。

第二行的是数据库连接URL,它实际上是数据库JDBC连接字符串的一部分。它的书写形式应该参考数据库驱动提供方的文档!

  • jdbc说明这是一个JDBC的连接字符串
  • mysql说明连接的数据库为MYSQL
  • localhost所在部分,一般是数据库的网络地址或域名,localhost实际上是一个域名,它在你系统的HOST文件中被解析到了127.0.0.1(通常是这样,不绝对,你完全可以修改它),这个地址是一个回环地址,它实际上表示你机器本身。同理,我的MySQL如果在远程服务器192.168.10.2上面,这里就不再是localhost,而是192.168.10.2或者对应的域名。
  • db_mybatis部分对应数据库名称,这个我们在之前创建过。
  • useUnicode这里的值为true表示使用Unicode编码,它是国际标准字符集,将世界上每一种自然语言每个字符都定义为一个唯一编码,满足跨语言需要,尤其是包含中文的时候。
  • characterEncoding部分是指定Unicode编码的存储方式。Unicode只是一个符号集,但并没有规定怎么存放。这里的存放方式为utf8,被定义为将码点编码为1到4个字节byte,具体取决于有效二进制位的数量。

类似于useUnicode的参数还有很多,比如设置SSL等,这里不过多介绍,碰到了请参考文档或搜索引擎。

jdbc.usernamejdbc.password就很简单了,一般是具有权限的数据库用户的用户名和密码。分配一个或多个具有部分权限的用户是好习惯,而不是一直用root(它权限太大了,不安全)。

app.xml

app.xml为Spring配置文件,名称同样不固定,根据你自己来。对于内容的解释请看下方代码的注释:

<!-- 指定XML版本和编码方式为Unicode UTF-8 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 指定需要扫描的包,使注解生效 --><context:component-scanbase-package="xxx.xxxx.xxx" /><!--读取db.properties --><context:property-placeholder location="classpath:db.properties"/><!-- 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><!--数据库驱动 --><property name="driverClassName" value="${jdbc.driver}" /><!--连接数据库的url --><property name="url" value="${jdbc.url}" /><!--连接数据库的用户名 --><property name="username" value="${jdbc.username}" /><!--连接数据库的密码 --><property name="password" value="${jdbc.password}" /></bean><!-- 事务管理器,依赖于数据源 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean>	<!-- 注册事务管理器驱动,开启事务注解 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 配置MyBatis工厂 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><!-- 这里指定了MyBatis配置文件为mybatis-config.xml --><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="xx.xxx.xx.mapper" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean></beans>

mybatis-config.xml

mybatis-config.xml为MyBatis配置文件,当然你可以不写它,将它的配置写在Spring配置文件中(写法不太一样),但不建议这么做,当文件内容特别多时不利于维护。

<?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="db.properties" /><settings><!-- 延迟加载的开关 --><setting name="lazyLoadingEnabled" value="false" /><!-- 设置积极加载(true)或按需加载(false) --><setting name="aggressiveLazyLoading" value="true" /><setting name="mapUnderscoreToCamelCase" value="true" /><setting name="logImpl" value="STDOUT_LOGGING" /></settings><typeAliases><!-- 对应的dao实体对象 --><package name="xx.xxx.xx.dao" /></typeAliases><!--2.配置Mapper的位置 --><mappers><mapper resource="xx/xxx/xx/mapper/CustomerMapper.xml" /></mappers>
</configuration>

log4j.properties

日志的配置文件

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.top.cairbin.test5=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

进程、线程与CPU调度

在开始Spring与MyBatis的整合之前,为了了解一些概念,我们来讲下进程与线程。

什么是进程?进程是对程序过程的抽象。它是OS的动态执行单元,在传统OS上既是基本分配单元又是基本执行单元。

举个不太严谨的例子,你在Windows下打开一个音乐播放器,随之你能在任务管理器中看到这一项,而这个正在运行的音乐播放器就是一个进程。

线程实际上算是轻量级的进程,但二者还是不太相同,不过它们的相同点要多余不同点。它是看起来就像是对计算机创建进程的模拟,只不过这个模拟是在进程之中的。

进程内存资源相对来讲较独立,而多个线程共享进程的内存资源。

另外我们的CPU调度一般是抢占式的,我们在使用计算机的时候看起来没啥感觉,但实际上CPU一直在“抽疯”——在多个线程之间进行高速切换,这就带来一些问题。

有些操作它不是原子的,即可分割为更小的操作,当一个活没有干完的时候,CPU便去干另一个活。

同时,多个线程尝试对同一个变量进行修改的时候,顺序可能是乱的。

这些都有可能导致线程不安全。什么是线程不安全?指多线程并发执行某个代码的时候,产生了逻辑上的错误,结果与预期值不同。

当然,内存可变性以及Java编译器对指令优化也有可能导致这种情况。

SqlSession

对于MyBatis来讲实际上有三种SqlSession,我们来分别讲讲它们的区别和使用场景。

首先看一张图片,描述再来描述它们的关系:

DefaultSqlSession

DefaultSqlSession类是SqlSession接口的默认实现,它通常被使用于执行SQL操作数据库。

//读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");// 构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();try {MyDao myDao = sqlSession.selectOne("MyMapper.selectDao", 1);System.out.println(myDao);
} finally {sqlSession.close();
}

DefaultSqlSession是一个线程不安全的,也就是说它不能是单例。

啥是单例?某些组件在整个程序运行时只要一个实例对象,多个实例化可能会报错。

DefaultSqlSession即然不能是单例,那每次从工厂中获取一个不就行了,实际上这会带来额外开销和资源重用。

另外,DefaultSqlSession还需要手动调用close()方法,这很容易忘记(虽然对于C++程序员是家常便饭),但是聪明的你肯定能用我们所学过的东西来解决这一问题吧——没错就是AOP。

我们既想要单例,又要线程安全,还想要自动关闭怎么办?这就有了SqlSessionManager

SqlSessionManager

SqlSessionManager使用了JDK动态代理技术(我们之前讲过),动态生成代理对象sqlSessionProxy,并通过SqlSessionInterceptor来对DefaultSqlSession进行增强。

虽然对于SqlSessionManager实际上还是创建非单例的DefaultSqlSession来执行方法,但SqlSessionManager可以是单例!

那你可能会怼我,说多个DefaultSqlSession这不还是会造成额外开销和资源重用吗?SqlSessionManager还有另外一种形态,它会复用线程本地的DefaultSqlSession

线程不安全是由于多个线程之间共享DefaultSqlSession导致的,那我在同线程内“共享”(复用)我自己的DefaultSqlSession那不就解决线程安全问题了吗。这就大大提高了效率。

治不了洋人还治不了你吗(雾)!

SqlSessionTemplate

SqlSessionTemplate是MyBatis与Spring整合时的线程安全SqlSession

SqlSessionTemplate实现线程安全的思路与SqlSessionManager相反,我既然自己管不了,我就让别人管——它交给SqlSessionUtils去获取SqlSession

但从本质上讲SqlSessionTemplateSqlSessionManager还是一样的。

SqlSessionUtils会先尝试从事务同步器中获取,获取不到再从工厂里要。而事务同步器本身就是一个线程本地变量管理器。

所以SqlSessionTemplateSqlSessionManager在实现线程安全这一点上殊途同归。

但是二者在自动关闭,即自动执行close()方法的时候就有区别了。

SqlSessionTemplate分两种情况:

  • 当获取的对象由事务同步管理器返回的时候,那关闭是交给Spring的。
  • 如果是从工厂里拿的,直接调用close()方法。

Spring与MyBatis整合

Spring与MyBatis整合方式分为两种:

  • 传统Dao方式
  • Mapper接口方式

传统Dao方式整合

采用传统的Dao方式整合Spring和MyBatis框架,可采用mybatis-spring中所提供的SqlSessionTemplate类或者SqlSessionDaoSupport类来实现。

由于这种方式在现在的开发中已经不常用了,所以这里仅做演示。

@Repository
public class CustomerDaoImpl extends SqlSessionDaoSupport implements ICustomerDao{@Autowiredpublic void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){super.sqlSessionFactory = sqlSessionFactory;}public void add(Customer customer){[...]}
}

更细化的讲解可参考Spring | 整合MyBatis中SqlSessionTemplate和MapperScannerConfigurer类的使用

Mapper接口方式

传统Dao方式会产生大量重复代码,而且需要正确指定映射文件中的id。

为了解决上述问题,我们采用Mapper的方式整合开发。

基于MapperFactoryBean的整合

MapperFactoryBean是MyBatis-Spring团队提供的一个用来根据Mapper接口生成Mapper对象的类,该类在配置文件中使用时可以配置一下参数

  • mapperInterface用于指定接口
  • SqlSessionFactory用于指定SqlSessionFactory
  • SqlSessionTemplate用于指定SqlSessionTemplate,如果与SqlSessionFactory同时设定,则一般情况下只会启用SqlSessionTemplate。

虽然使用Mapper接口编程的方式很简单,但是在具体使用的时候还是需要遵循一些规范:

  • Mapper接口的名称和对应的XML映射文件名称必须一致
  • XML映射文件中的namespace与Mapper接口的类路径相同
  • Mapper接口方法名要和XML映射文件中定义的每个执行语句的id相同
  • Mapper接口中的方法的输入参数类型和XML映射文件中的parameterType类型相同
  • Mapper接口方法的输出类型要和XML映射文件的resultType类型相同
基于MapperScannerConfigurer的方式

使用上面的方式会使得配置文件臃肿,所以我们在做项目开发的时候一般是使用MapperScannerCongigurer的方式进行扫描。

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="top.cairbin.test6.mapper" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

我们新建一个项目top.cairbin.test6,至于哪些细节该注意你应当非常清楚了,这里就不多说了,如果不会请回去看之前的教程。

对于配置文件我们也说的很清楚了,接下来直接给文件:

pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>top.cairbin</groupId><artifactId>test6</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>test6</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.7</maven.compiler.source><maven.compiler.target>1.7</maven.compiler.target><junit.version>4.12</junit.version><spring.version>5.2.5.RELEASE</spring.version><mybatis.version>3.5.4</mybatis.version><mybatis.spring.version>2.0.4</mybatis.spring.version><mysql.version>8.0.33</mysql.version><commons-dbcp.version>2.7.0</commons-dbcp.version></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency>		<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis.spring.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>${commons-dbcp.version}</version></dependency><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.4.0</version></dependency>		</dependencies>
</project>

db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=db_mybatis
jdbc.password=db_mybatis

Spring配置文件app.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 指定需要扫描的包,使注解生效 --><context:component-scanbase-package="top.cairbin.test6" /><!--读取db.properties --><context:property-placeholder location="db.properties"/><!-- 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><!--数据库驱动 --><property name="driverClassName" value="${jdbc.driver}" /><!--连接数据库的url --><property name="url" value="${jdbc.url}" /><!--连接数据库的用户名 --><property name="username" value="${jdbc.username}" /><!--连接数据库的密码 --><property name="password" value="${jdbc.password}" /></bean><!-- 事务管理器,依赖于数据源 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean>	<!-- 注册事务管理器驱动 --><tx:annotation-driven transaction-manager="transactionManager"/><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="mybatis-config.xml"/></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="top.cairbin.test6.mapper" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean>
</beans>

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><properties resource="db.properties" /><settings><!-- 延迟加载的开关 --><setting name="lazyLoadingEnabled" value="false" /><!-- 设置积极加载(true)或按需加载(false) --><setting name="aggressiveLazyLoading" value="true" /><setting name="mapUnderscoreToCamelCase" value="true" /><setting name="logImpl" value="STDOUT_LOGGING" /></settings><typeAliases><package name="top.cairbin.test6.dao" /></typeAliases><!--2.配置Mapper的位置 --><mappers><mapper resource="top/cairbin/test6/mapper/CustomerMapper.xml" /></mappers>
</configuration>

top.cairbin.test6.dao.Customer

package top.cairbin.test6.dao;public class Customer {private Integer id;			// 主键idprivate String username;	// 客户名称private String jobs;		// 职业private String phone;		// 电话public Integer getId() {return this.id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return this.username;}public void setUsername(String username) {this.username = username;}public String getJobs() {return this.jobs;}public void setJobs(String jobs) {this.jobs = jobs;}public String getPhone() {return this.phone;}public void setPhone(String phone) {this.phone = phone;}@Overridepublic String toString() {return "Customer [id=" + id + ", username=" + username + ", jobs=" + jobs + ", phone=" + phone + "]";}
}

top.cairbin.test6.mapper下的CustomerMapper.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="top.cairbin.test6.mapper.CustomerMapper"><resultMap id="BaseResultMap" type="top.cairbin.test6.dao.Customer"><id column="id" jdbcType="INTEGER" property="id" /><result column="username" jdbcType="VARCHAR" property="username" /><result column="jobs" jdbcType="VARCHAR" property="jobs" /><result column="phone" jdbcType="VARCHAR" property="phone" /></resultMap><sql id="Base_Column_List">id, username, jobs, phone</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from customerwhere id = #{id,jdbcType=INTEGER}</select>
</mapper>

对应接口top.cairbin.test6.mapper.CustomerMapper

package top.cairbin.test6.mapper;import top.cairbin.test6.dao.Customer;public interface CustomerMapper{// 通过id查询客户Customer selectByPrimaryKey(Integer id);
}

我们接下来实现Service层

创建src/main/java下的包top.cairbin.test6.service

然后在包中创建接口ICustomerService

package top.cairbin.test6.service;import top.cairbin.test6.dao.Customer;public interface ICustomerService {	public Customer getCustomerByID(int id);
}

创建实现这个接口的类CustomerServiceImpl

package top.cairbin.test6.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.cairbin.test6.dao.Customer;
import top.cairbin.test6.mapper.CustomerMapper;@Service
public class CustomerServiceImpl implements ICustomerService{@Autowiredprivate CustomerMapper customerMapper;public Customer getCustomerByID(int id) {Customer customer = customerMapper.selectByPrimaryKey(id);return customer;}
}

在测试目录src/test/java下的top.cairbin.test6包创建测试类CustomerTest

package top.cairbin.test6;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import top.cairbin.test6.dao.Customer;
import top.cairbin.test6.service.ICustomerService;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:app.xml" })
public class CustomerTest {@Autowiredprivate ICustomerService customerService;	@Testpublic void findTest() {Customer customer = customerService.getCustomerByID(1);System.out.println(customer);}
}

运行测试,得到结果

相关文章:

SSM框架学习——SqlSession以及Spring与MyBatis整合

SqlSession以及Spring与MyBatis整合 准备所需要的JAR包 要实现MyBatis与Spring的整合&#xff0c;很明显需要这两个框架的JAR包&#xff0c;但是只是使用这两个框架中所提供的JAR包是不够的&#xff0c;还需要配合其他包使用&#xff1a; Spring的JAR包MyBatis的JAR包Spring…...

6、【单例模式】确保了一个类在程序运行期间只有一个实例

你好&#xff0c;我是程序员雪球 在软件设计中&#xff0c;单例模式是一种常见的设计模式。它确保了一个类在程序运行期间只有一个实例&#xff0c;并提供了全局访问该实例的方式。单例模式在许多场景中都有广泛的应用&#xff0c;例如共享资源管理、数据库连接、日志记录器等…...

vuex插件实现数据共享

vuex插件 vuex是管理多个vue通用的数据的插件.(状态管理工具,状态是数据) 我们对于多个vue文件之间的共同数据,是用props传递,或者对于一个vue实例对象,进行绑定,传参,也是多次传参,多个文件之间,比较麻烦. 但是我们vuex会创建一个公共对象,从这个公共对象上赋值,比较简单易…...

【吊打面试官系列】Redis篇 - 使用过 Redis 分布式锁么,它是什么回事?

大家好&#xff0c;我是锋哥。今天分享关于 【使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f; 先拿 setnx 来争抢锁&#xff0c;抢到之后&#…...

DashOJ-8.奇偶统计

题目链接&#xff1a; 题目详情 - 奇偶统计 - DashOJ 思路&#xff1a; &#xff08;while循环加if分支语句&#xff09; 巧用死循环 while(1) 然后在里面第一句就判断输入的数字是否等于0 if(x0) &#xff0c;如果 等于0就直接break跳出循环 或者用 while(cin>>x) 代…...

车源宝微信小程序源码

源码介绍 车源宝微信小程序源码 images — 存放项目图片文件 pages — 存放项目页面相关文件 store — 存放数据接口文件 utils — 存放时间格式化等文件 演示截图 源码下载 https://download.csdn.net/download/huayula/89082980...

“双碳”目标下资源环境中的可计算一般均衡(CGE)模型应用

我国政府承诺在2030年实现“碳达峰”&#xff0c;2060年实现“碳中和”&#xff0c;这就是“双碳”目标。为了实现这一目标就必须应用各种二氧化碳排放量很高技术的替代技术&#xff0c;不仅需要考虑技术上的可靠性&#xff0c;也需要考虑经济上的可行性。可计算一般均衡模型&a…...

在 Git Bash 中调整字体大小,可以按照以下步骤进行操作,注意这里是linux虚拟机,命令都是Linux方式的

在 Git Bash 中调整字体大小&#xff0c;可以按照以下步骤进行操作&#xff1a; 打开 Git Bash 终端。 在终端中&#xff0c;点击顶部菜单栏的 "Options"&#xff08;选项&#xff09;。 在弹出的下拉菜单中&#xff0c;选择“text”文本 右侧font那里&#xf…...

STM32之HAL开发——不同系列SPI功能对比(附STM32Cube配置)

不同系列STM32——SPI框图 F1系列框图 F4系列框图 TI模式时序图特性 F7系列框图 H7系列框图 注意&#xff1a;F7系列以及H7系列支持Quad-SPI模式&#xff0c;可以连接单&#xff0c;双或者四条数据线的Flash存储介质。 SPI——Cube配置流程 RCC时钟源配置 SYS系统调试模式配…...

Codeforces Round 836 (Div. 2) D. Range = √Sum

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5; c…...

阿里云python-SDK配置

OSS管理控制台 (aliyun.com) SDK地址 GitHub - aliyun/aliyun-oss-python-sdk: Aliyun OSS SDK for Python 下载文件并运行 python setup.py install oss2包配置完成。 上传、下载开发文档&#xff1a; Python SDK快速入门_对象存储(OSS)-阿里云帮助中心 (aliyun.com)...

深入理解MP4视频文件裁剪原理[下下]

深入理解MP4视频文件裁剪原理[上] 深入理解MP4视频文件裁剪原理[中] 深入理解MP4视频文件裁剪原理[下] 深入理解MP4视频文件裁剪原理[下下] 3.22 stco box* stco box记录了每个chunk在MP4文件中的偏移量。如下图24: 图24 这里的offset指的是chunk的起始位置相对于整个MP4文…...

Java中copy 一个list,不用BeanUtils.copyProperties

1.List不起作用&#xff08;单个对象拷贝有用&#xff0c;list没有用&#xff09; cn.hutool.core.bean.BeanUtils.copyProperties(a, b); org.springframework.beans.BeanUtils.copyProperties(a, b); 2.有效&#xff08;使用JSONObject 先转成字符串再转成List对象&#x…...

Vue3中props和emits的使用总结

Vue3中props和emits的使用介绍 1&#xff0c;看代码1.1&#xff0c;App.vue1.2&#xff0c;TodoItem.vue 2&#xff0c;总结2.1 props2.2 emits 1&#xff0c;看代码 1.1&#xff0c;App.vue <script setup> import { ref,reactive } from vue import TodoItem from ./…...

HUAWEI 华为交换机 配置 Eth-Trunk 接口流量本地优先转发示例(堆叠)

组网需求 说明 S5720I-10X-PWH-SI-AC 和 S5720I-6X-PWH-SI-AC 不支持此配置。 如 图 3-23 所示&#xff0c;为了增加设备的容量采用设备堆叠技术&#xff0c;将 Switch3 和 Switch4通过专用的堆叠电缆链接起来&#xff0c;对外呈现为一台逻辑交换机。为了实现设备间的备份、…...

MySQL 优化及故障排查

目录 一、mysql 前置知识点 二、MySQL 单实例常见故障 故障一 故障二 故障三 故障四 故障五 故障六 故障七 故障八 三、MySQL 主从故障排查 故障一 故障二 故障三 四、MySQL 优化 1.硬件方面 &#xff08;1&#xff09;关于 CPU &#xff08;2&#xff09;关…...

H12-821_182

182.当0SPF运行在广播型网络中时&#xff0c;需要选举DR和BDR。那么以下哪一种状态会进行DR和BDR的选举? A.2-way B.Full C.Exchange D.Init 答案&#xff1a;A 注释&#xff1a; 每台路由器发送的hello报文都有DR字段和BDR字段。 路由器接口刚开始运行OSPF时&#xff0c;在等…...

IF语句

目录 if...then 数字大小的比较 if...then...else 比较两个数字的大小 if...then...elsif 根据输入的数字大小&#xff0c;判断学生成绩范围&#xff08;优&#xff1a;90~100&#xff1b;良&#xff1a;80~89&#xff1b;中&#xff1a;70~79&#xff1b;及格&#xff1…...

AttributeError: module ‘wandb‘ has no attribute ‘init‘解决办法

安装对应的库 pip install wandb -i https://pypi.tuna.tsinghua.edu.cn/simple拓展——wandb是什么模块&#xff0c;有什么作用 wandb是一个用于跟踪、可视化和协作机器学习项目的工具。它提供了许多功能&#xff0c;包括实时的指标跟踪、超参数调整、模型的可视化等&#x…...

javaScript中微任务宏任务详解

在 JavaScript 中&#xff0c;任务分为两种类型&#xff1a;微任务&#xff08;Microtask&#xff09;和宏任务&#xff08;Macrotask&#xff09;。它们的执行顺序以及在事件循环&#xff08;Event Loop&#xff09;中的位置不同。 微任务&#xff08;Microtask&#xff09;&…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...