Spring Boot中配置多个数据源

配置数据源实际上就是配置多个数据库,在一个配置文件中配置多个数据库,这样做主要的好处有以下几点:

  1. 数据库隔离:通过配置多个数据源,可以将不同的业务数据存储在不同的数据库中,实现数据的隔离。这样可以提高系统的安全性和稳定性,避免不同业务之间的数据相互干扰。
  2. 性能优化:通过配置多个数据源,可以将读写操作分离到不同的数据库中,从而提高系统的并发性能。例如,将读操作集中在一个主数据库中,将写操作分散到多个从数据库中,可以有效地减轻数据库的读写压力,提高系统的响应速度。
  3. 扩展性:当系统需要扩展到多个地理位置或多个数据中心时,配置多个数据源可以更好地支持分布式部署。每个地理位置或数据中心可以配置一个独立的数据源,使得数据访问更加高效和可靠。
  4. 多租户支持:对于多租户的系统,配置多个数据源可以实现不同租户的数据隔离。每个租户可以拥有自己独立的数据库,从而保证数据的安全性和隐私性。
  5. 数据库版本升级:在进行数据库版本升级时,可以通过配置多个数据源,将新版本的数据库与旧版本的数据库并行使用。这样可以在升级过程中保证系统的正常运行,减少升级带来的风险。

我们目前常用的三种数据访问方法方式:

  1. JDBCTemplate
  2. Spring Data JPA
  3. MyBatis

接下来我们将围绕这种数据访问方法进行配置:

JDBCTemplate

实际上这种方式,主要还是在application.properties中设置我们需要链接的数据库配置,比如我A数据库用来存储用户信息,B数据库用来存储业务数据。

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

ok,我们继续配置完毕后数据源后,我们就通过配置类来完成加载这些配置信息,初始话数据源,以及初始化每个数据源的时候要用的JDBCTemplate。你只需要在你的Spring Boot中应用下面的配置类就可以完成。

@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        return new JdbcTemplate(primaryDataSource);
    }

    @Bean
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        return new JdbcTemplate(secondaryDataSource);
    }

}
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

单元测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Autowired
    protected JdbcTemplate primaryJdbcTemplate;

    @Autowired
    protected JdbcTemplate secondaryJdbcTemplate;

    @Before
    public void setUp() {
        primaryJdbcTemplate.update("DELETE  FROM  USER ");
        secondaryJdbcTemplate.update("DELETE  FROM  USER ");
    }

    @Test
    public void test() throws Exception {
        // 往第一个数据源中插入 2 条数据
        primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "aaa", 20);
        primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "bbb", 30);

        // 往第二个数据源中插入 1 条数据,若插入的是第一个数据源,则会主键冲突报错
        secondaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "ccc", 20);

        // 查一下第一个数据源中是否有 2 条数据,验证插入是否成功
        Assert.assertEquals("2", primaryJdbcTemplate.queryForObject("select count(1) from user", String.class));

        // 查一下第一个数据源中是否有 1 条数据,验证插入是否成功
        Assert.assertEquals("1", secondaryJdbcTemplate.queryForObject("select count(1) from user", String.class));
    }
}

有两个JdbcTemplate,为什么不用@Qualifier指定?这里顺带说个小知识点,当我们不指定的时候,会采用参数的名字来查找Bean,存在的话就注入。

这两个JdbcTemplate创建的时候,我们也没指定名字,它们是如何匹配上的?这里也是一个小知识点,当我们创建Bean的时候,默认会使用方法名称来作为Bean的名称,所以这里就对应上了。读者不妨回头看看两个名称是不是一致的。

Spring Data JPA

和上边那种方式基本上类似,所做的操作会有细微的区别。

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

配置application.properties文件

# pring boot 1.x的配置:spring.datasource.primary.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

# spring boot 1.x的配置:spring.datasource.secondary.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

# 日志打印执行的SQL
spring.jpa.show-sql=true
# Hibernate的DDL策略
spring.jpa.hibernate.ddl-auto=create-drop

创建实体类:

@Entity
//@Data
//@NoArgsConstructor
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public User() {
    }
}
public interface UserRepository extends JpaRepository<User, Long> {

}
@Entity
//@Data
//@NoArgsConstructor
public class Message {

    @Id
    @GeneratedValue
    private Long id;

    private String title;
    private String message;

    public Message(String title, String message) {
        this.title = title;
        this.message = message;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Message() {
    }
}
public interface MessageRepository extends JpaRepository<Message, Long> {


}

多数据源配置类:

@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

主数据源配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryPrimary",
        transactionManagerRef="transactionManagerPrimary",
        basePackages= { "com.miaow.demo.p" }) //设置Repository所在位置
public class PrimaryConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;

    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }

    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
//        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
//        jpaVendorAdapter.setGenerateDdl(true);
        return builder
                .dataSource(primaryDataSource)
                .packages("com.miaow.demo.p") //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .properties(getVendorProperties())
                .build();
    }

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }
}

设置从数据库配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactorySecondary",
        transactionManagerRef="transactionManagerSecondary",
        basePackages= { "com.miaow.demo.s" }) //设置Repository所在位置
public class SecondaryConfig {

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;

    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .packages("com.miaow.demo.s") //设置实体类所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .properties(getVendorProperties())
                .build();
    }

    @Bean(name = "transactionManagerSecondary")
    PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }

}

创建的单元测试:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private MessageRepository messageRepository;

    @Test
    public void test() throws Exception {
        userRepository.save(new User("aaa", 10));
        userRepository.save(new User("bbb", 20));
        userRepository.save(new User("ccc", 30));
        userRepository.save(new User("ddd", 40));
        userRepository.save(new User("eee", 50));

        Assert.assertEquals(5, userRepository.findAll().size());

        messageRepository.save(new Message("o1", "aaaaaaaaaa"));
        messageRepository.save(new Message("o2", "bbbbbbbbbb"));
        messageRepository.save(new Message("o3", "cccccccccc"));

        Assert.assertEquals(3, messageRepository.findAll().size());
    }

}

MyBatis

在Spring Boot的配置文件application.properties中设置我们需要的两个连接的数据库配置:

# pring boot 1.x的配置:spring.datasource.primary.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

# spring boot 1.x的配置:spring.datasource.secondary.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

#mybatis.mapper-locations=classpath:mapper/*.xml

创建一个初始化多数据源和MyBatis配置

@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

可以看到内容跟JdbcTemplateSpring Data JPA的时候是一模一样的。通过@ConfigurationProperties可以知道这两个数据源分别加载了spring.datasource.primary.*spring.datasource.secondary.*的配置。@Primary注解指定了主数据源,就是当我们不特别指定哪个数据源的时候,就会使用这个Bean真正差异部分在下面的JPA配置上。

分别创建这两个数据源的MyBatis配置文件:
Private 数据源的JPA的配置文件:

@Configuration
@MapperScan(
        basePackages = "com.miaow.demo.p",
        sqlSessionFactoryRef = "sqlSessionFactoryPrimary",
        sqlSessionTemplateRef = "sqlSessionTemplatePrimary")
public class PrimaryConfig {

    private DataSource primaryDataSource;

    public PrimaryConfig(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        this.primaryDataSource = primaryDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryPrimary() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(primaryDataSource);
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplatePrimary() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryPrimary());
    }

}

Secondary的数据源JPA配置:

@Configuration
@MapperScan(
        basePackages = "com.miaow.demo.s",
        sqlSessionFactoryRef = "sqlSessionFactorySecondary",
        sqlSessionTemplateRef = "sqlSessionTemplateSecondary")
public class SecondaryConfig {

    private DataSource secondaryDataSource;

    public SecondaryConfig(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        this.secondaryDataSource = secondaryDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactorySecondary() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(secondaryDataSource);
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateSecondary() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactorySecondary());
    }

}

注意在此说明一下,配置类上使用@MapperScan注解来指定当前数据源下定义的EntityMapper的包路径;
另外需要指定sqlSessionFactorysqlSessionTemplate,这两个具体实现在该配置类中类中初始化。
配置类的构造函数中,通过@Qualifier注解来指定具体要用哪个数据源,其名字对应在DataSourceConfiguration配置类中的数据源定义的函数名。
配置类中定义SqlSessionFactorySqlSessionTemplate的实现,注意具体使用的数据源正确。

创建一个UserPrimary实体类:

public class UserPrimary {

    private Long id;


    private String name;
    private Integer age;

    public UserPrimary(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public UserPrimary() {
    }
}

创建一个UserMapperPrimary用来作为填写SQL语句的接口:

public interface UserMapperPrimary {

    @Select("SELECT * FROM USER WHERE NAME = #{name}")
    UserPrimary findByName(@Param("name") String name);

    @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

    @Delete("DELETE FROM USER")
    int deleteAll();

}

创建一个UserSecondary实体类:

public class UserSecondary {

    private Long id;

    private String name;
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public UserSecondary() {
    }

    public UserSecondary(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
public interface UserMapperSecondary {

    @Select("SELECT * FROM USER WHERE NAME = #{name}")
    UserSecondary findByName(@Param("name") String name);

    @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

    @Delete("DELETE FROM USER")
    int deleteAll();
}

之后,也是最关键的一步,我们需要在MyBatis的配置文件中使用Mapper.xml
在Resources目录下创建一个mapper文件夹,之后再mapper文件夹下边分别创建primary和secondary文件夹:
在这里插入图片描述
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.miaow.demo.p.mapper.UserMapperPrimary">
    <select id="findByName" resultType="com.miaow.demo.p.entity.UserPrimary">
        SELECT * FROM USER WHERE NAME = #{name}
    </select>

    <insert id="insert">
        INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})
    </insert>

</mapper>

与上边这个几乎一样,只是两者指向的接口位置不一样:

<?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.miaow.demo.s.mapper.UserMapperSecondary">

    <select id="findByName" resultType="com.miaow.demo.s.entity.UserSecondary">
        SELECT * FROM USER WHERE NAME = #{name}
    </select>

    <insert id="insert">
        INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})
    </insert>

</mapper>

最后我们可以通过一个测试类进行测试:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class ApplicationTests {

//第一数据库配置类
    @Autowired
    private UserMapperPrimary userMapperPrimary;
    //第二数据库配置文件
    @Autowired
    private UserMapperSecondary userMapperSecondary;

    @Before
    public void setUp() {
        // 清空测试表,保证每次结果一样
        userMapperPrimary.deleteAll();
        userMapperSecondary.deleteAll();
    }

    @Test
    public void test() throws Exception {
        // 往Primary数据源插入一条数据
        userMapperPrimary.insert("AAA", 20);

        // 从Primary数据源查询刚才插入的数据,配置正确就可以查询到
        UserPrimary userPrimary = userMapperPrimary.findByName("AAA");
        Assert.assertEquals(20, userPrimary.getAge().intValue());

        // 从Secondary数据源查询刚才插入的数据,配置正确应该是查询不到的
        UserSecondary userSecondary = userMapperSecondary.findByName("AAA");
        Assert.assertNull(userSecondary);

        // 往Secondary数据源插入一条数据
        userMapperSecondary.insert("BBB", 20);

        // 从Primary数据源查询刚才插入的数据,配置正确应该是查询不到的
        userPrimary = userMapperPrimary.findByName("BBB");
        Assert.assertNull(userPrimary);

        // 从Secondary数据源查询刚才插入的数据,配置正确就可以查询到
        userSecondary = userMapperSecondary.findByName("BBB");
        Assert.assertEquals(20, userSecondary.getAge().intValue());
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安全易用的文件同步程序:Syncthing | 开源日报 No.70

syncthing/syncthing Stars: 55.0k License: MPL-2.0 Syncthing 是一个持续文件同步程序&#xff0c;它在两台或多台计算机之间同步文件。该项目的主要功能和核心优势包括&#xff1a; 安全防止数据丢失抵御攻击易于使用自动化操作&#xff0c;仅在必要时需要用户交互适合在各…

Pytest系列(16)- 分布式测试插件之pytest-xdist的详细使用

前言 平常我们功能测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟&#xff0c;如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时&#xff0c;会需要协调多个测试资源来把任务分成两部分&#xff0c;于是执行时间缩短一半&#…

船舶数据采集与数据模块解决方案

标准化信息处理单元原理样机初步方案&#xff1a; 1&#xff09;系统组成 标准化信息处理单元原理样机包含硬件部分和软件部分。 硬件部分包括集成电路板、电源模块、主控模块、采集模块、信息处理模块、通讯模块、I/O模块等。 软件部分包括协议统一标准化模块、设备互联互…

R语言将向量横向转换为单行数据框,随后整合数量不确定的数据框

vector1 c(1, “karthik”, “IT”) names(vector1) c(“id”, “name”, “branch”) df data.frame(as.list(vector1)) print(df) 先给向量的元素命名&#xff0c;然后转换为列表&#xff0c;最后转换为数据框。 我的需求大概是这个样子&#xff1a;数量不确定的仅有单行…

猫罐头怎么选?千万别错过这5款好吃放心的猫罐头推荐!

猫罐头不仅美味可口&#xff0c;而且营养丰富&#xff0c;是专为猫咪打造的美食。那么&#xff0c;猫罐头怎么选&#xff1f;作为一位经营宠物店7年的店长&#xff0c;我对猫猫的饮食都非常重视&#xff0c;也见证了很多猫咪品尝各种猫罐头的瞬间&#xff0c;现在我对各个品牌的…

信创加速,美创科技加入UOS主动安全防护计划(UAPP)

近日&#xff0c;统信UOS主动安全防护计划 (UAPP) 技术沙龙暨新老会员交流活动在北京召开。 美创科技作为信创产业的重要参与者受邀参加。在2023年度UAPP合作伙伴授牌发布仪式上&#xff0c;美创科技获得统信软件授牌&#xff0c;正式成为UAPP成员单位&#xff0c;将与统信软件…

共话医疗数据安全,美创科技@2023南湖HIT论坛,11月11日见

11月11日浙江嘉兴 2023南湖HIT论坛 如约而来 深入数据驱动运营管理、运营数据中心建设、数据治理和数据安全、数据资产“入表”等热点、前沿话题 医疗数据安全、数字化转型深耕者—— 美创科技再次深入参与 全新发布&#xff1a;医疗数据安全白皮书 深度探讨&#xff1a;数字…

详细创建Prism架构wpf项目

方案一&#xff1a; 1.创建一个普通wpf项目 2、安装NuGet包&#xff1a;Prism.DryIoc 3、App.xaml.cs中: 将原本的父类Application改为&#xff1a;PrismApplication&#xff0c;并且实现抽象类 CreateShell方法中写上&#xff1a;”return Container.Resolve<MainWindow>…

分享4个MSVCP100.dll丢失的解决方法

msvcp100.dll是一个重要的动态链接库文件&#xff0c;它是Microsoft Visual C 2010 Redistributable Package的一部分。这个文件的作用是提供在运行C程序时所需的函数和功能。如果计算机系统中msvcp100.dll丢失或者损坏&#xff0c;就会导致软件程序无法启动运行&#xff0c;会…

【STM32】HAL库UART含校验位的串口通信配置BUG避坑

【STM32】HAL库UART含校验位的串口通信配置BUG避坑 文章目录 UART协议校验位HAL库配置含校验位的串口配置BUG避坑附录&#xff1a;Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作SysTick系统定时器精准延时延时函数阻塞延时非阻塞延时 位带操作位带代码位带宏定义总线函…

2023年萤石C6C系列监控如何设置群晖Surveillance网络摄像机套件教程

2023年萤石C6C系列监控如何设置群晖Surveillance网络摄像机套件教程 前置工作莹石云视频App设置群晖Nas设置温馨提醒 前置工作 按照说明书安装好莹石监控摄像机&#xff0c;确保机器正常运作&#xff1b;设置好莹石云视频App&#xff0c;确保能够正常查看监控视频。在群晖Nas的…

RocketMQ常用管理命令

MQAdmin是RocketMQ自带的命令行管理工具&#xff0c;在bin目录下&#xff0c;运行mqadmin即可执行。使用mqadmin命令&#xff0c;可以进行创建、修改Topic&#xff0c;更新Broker的配置信息&#xff0c;查询特定消息等各种操作。本节将介绍几个常用的命令。 1.创建/修改Topic …

基于STC15单片机温度光照蓝牙传输-proteus仿真-源程序

一、系统方案 本设计采用STC15单片机作为主控器&#xff0c;液晶1602显示&#xff0c;DS18B20采集温度&#xff0c;光敏电阻采集光照、按键设置温度上下限&#xff0c;测量温度小于下限&#xff0c;启动加热&#xff0c;测量温度大于上限&#xff0c;启动降温。 二、硬件设计 …

聚观早报 |GPT-4周活用户数达1亿;长城汽车10月销量增加

【聚观365】11月8日消息 GPT-4周活用户数达1亿 长城汽车10月销量增加 xAI宣布推出PromptIDE工具 aigo爱国者连发5款儿童手表 SpaceX预计今年营收90亿美元 GPT-4周活用户数达1亿 在OpenAI首届开发者大会上&#xff0c;该公司首席执行官萨姆奥特曼&#xff08;Sam Altman&a…

Linux内核分析(九)--CPU上下文

目录 一、引言 二、CPU上下文 ------>2.1、CPU上下文切换 三、线程上下文切换 ------>3.1、协程 四、中断上下文切换 ------>4.1、vmstat ------>4.2、pidstat ------>4.3、sysbench 一、引言 Linux是一个多任务的操作系统,可以支持远大于CPU数量的…

java项目之高校推免报名(ssm框架)

项目简介 高校推免报名实现了以下功能&#xff1a; 管理员功能&#xff1a;管理员登陆后&#xff0c;主要模块包括首页、个人中心、考生管理、报名指南管理、报名入口管理、专业信息管理、考生报名管理、考生成绩管理、面试通知管理、参加面试管理、面试成绩管理、综合成绩管…

Springboot养老院信息管理系统的开发-计算机毕设 附源码27500

Springboot养老院信息管理系统的开发 摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;…

2023首届中国水果互联网上海论坛成功举办!

11月7日&#xff0c;“2023首届中国水果互联网上海论坛“在上海浦东嘉里大酒店成功举办&#xff0c;本次论坛是推动水果行业产业互联网发展的重要活动&#xff0c;也是中国水果互联网论坛的系列活动之一。 “2023首届中国水果互联网上海论坛”是由亚果会和亚果学社联合发起&…

【工具】OCR方法|不用下载额外的软件,提取扫描中英文PDF的目录文本的最优解!(一)

需求&#xff1a; 1&#xff09;从PDF里快速提取目录&#xff1b; 2&#xff09;不想下载任何软件。 我提取出来的目录文本会用于嵌入到PDF中&#xff0c;向PDF批量添加目录的软件以及软件的使用方法可以看我上一篇文章&#xff1a;PDF批量插入目录。 以下是我自己能想到的方…

leetcode做题笔记226. 翻转二叉树

给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]示例 3&#x…
最新文章