怎么使用数据库查询内容注入spring容器,并使该对象与数据库同步更新

@Conmponen 
public class TestDemo{

@Autowired
private Date businessDate;

@Autowired
private BusinessDateMapper businessDateMapper;

@Bean
private Date businessDate(){
  return businessDateMapper.getOne;
}

publict void test(){
  System.out.printlan(businessDate);
}

}

businessDateMapper.getOne的内容会每天更新,这个test()方法中使用businessDate时,会每天和数据库同步更新吗?
能具体说下
@Bean
private Date businessDate()
的更新原理吗? 以及
@Autowired
private Date businessDate;这个注入对象的刷新时机

不会的,Bean组件以及Autowired在项目刚刚启动的时候就会注入到系统中,也就是说这个值在项目启动的时候会改变,后续的时候将不会变更了。其实这里的做法可以使用定时任务去刷businessDate这个值,保持和数据库里面的值一样

以下答案基于ChatGPT与GISer Liu编写:
①首先,让我们解释一下这段代码的作用:

这段代码使用Spring Framework中的注解来创建一个组件(Component),即名为“测试演示”的公共类。其中,“测试演示”类使用了一个私有业务日期(private businessDate)作为类成员变量,并且该变量被注入到Spring容器中。通过@Bean注解的私有日期业务日期方法,该变量将被注入到Spring容器中并进行依赖注入。此外,还使用@Autowired注解将私有业务日期注入到私人约会业务日期和私人业务日期映射器业务日期映射器中。

②回到你的问题,当你在调用test()方法时,Spring会从容器中获取私有业务日期bean的实例,并且如果这个bean的作用域是singleton(单例),则在整个应用程序的生命周期中,只会有一个实例。当调用businessDateMapper.getOne()方法时,它将返回数据库中的最新值,并且这个值将被存储在bean实例中。

  • 在这种情况下,由于我们使用的是默认的单例作用域(singleton scope),因此当你调用test()方法时,只会有一个实例,并且在调用businessDateMapper.getOne()方法时,它会每天从数据库中获取最新的值并更新实例。

  • 如果你想要更改作用域或实现更高级的更新逻辑,则可以通过使用其他作用域(如prototype、session、request等)或通过编写适当的逻辑来实现自定义的更新行为。

  • 对于@Autowired private Date businessDate;注入对象的刷新时机,与bean的作用域有关。如果作用域是singleton,则该bean将在应用程序启动时创建,并且只有一个实例,因此在整个应用程序的生命周期中,businessDate的值将不会更新。如果作用域是原型,则每次注入时都会创建一个新的实例,因此每次使用时都会获取最新的值。其他作用域的行为将取决于具体的实现方式。

不会的,你这种写法只会服务启动的时候加载一次,不知道你的更新频率和更新时间是否固定,是每天更新一次还是多次更新,建议写个定时器实现,如果每天更新一次,可以在内容更新完一分钟后去获取,如果是经常更新,就设置成每几分钟或者什么时间去更新。

参考GPT和自己的思路,首先,关于使用数据库查询内容注入Spring容器,可以使用@Bean注解来实现,将查询到的数据作为Bean的实例返回给Spring容器管理。

在代码中,通过@Bean注解定义了一个名为businessDate的方法,该方法返回的是从BusinessDateMapper中查询出的一条数据。因为@Bean注解在方法上,所以该方法返回的实例会被Spring容器管理,并可以被其他类使用@Autowired注解注入。

当Spring容器启动时,会调用businessDate()方法并将其返回的实例添加到容器中,同时@Autowired注解会在需要使用businessDate对象的地方注入该实例。

因为业务日期每天都会更新,所以在调用businessDate()方法时,实际上是每次都从数据库中查询最新的数据并返回。这意味着,每次使用businessDate对象时都会使用最新的数据。

因为businessDate是一个Spring Bean,在使用时会从Spring容器中获取实例。Spring容器会在需要该Bean实例时进行实例化,而实例化时会再次调用businessDate()方法从数据库中查询最新数据。因此,即使在应用运行期间数据库中的数据发生了变化,使用businessDate对象时也会使用最新的数据。

需要注意的是,因为@Bean注解默认是使用单例模式创建Bean实例,所以每次使用businessDate对象时都会使用同一个实例。如果希望每次使用时都获取最新的数据,可以将@Bean注解的scope属性设置为prototype,这样每次都会创建一个新的实例。

关于@Autowired注解的刷新时机,当使用@Autowired注解注入的对象的作用域是singleton(默认值)时,对象只会在应用启动时创建一次,并且在应用生命周期内保持不变。当使用的作用域是prototype时,每次注入时都会创建一个新的实例。

因此,在上述代码中,因为businessDate对象是使用默认的singleton作用域注入的,所以它只会在应用启动时创建一次,并且在应用生命周期内保持不变,直到应用停止。如果希望在每次使用businessDate对象时都获取最新的数据,可以将其作用域设置为prototype。

在你的这个例子中,businessDate方法通过@Autowired注解自动注入到TestDemo类中的businessDate字段。Spring容器在实例化TestDemo时将自动调用businessDate方法,以获得Date类型的对象并将其注入到businessDate字段中。由于businessDate方法返回的对象是通过businessDateMapper.getOne方法从数据库中获取的,因此它会在每次调用businessDate方法时从数据库中获取最新的值。如果业务需要在每天更新时同步更新businessDate对象,可以使用@Scheduled注解设置定时任务,以在特定时间自动调用业务逻辑更新businessDateMapper中的数据。在定时任务中,可以调用businessDateMapper.getOne方法更新数据库中的值,并通过调用businessDate方法从Spring容器中获取最新的对象。由于业务逻辑更新了数据库中的值,因此在下一次调用businessDate方法时,将会获取最新的值。

要使用数据库查询内容注入Spring容器,您可以执行以下步骤:

创建一个Java类,该类将表示您从数据库中检索的数据。这个类需要具有与数据库表中的列对应的属性。

使用Spring的JDBC支持或ORM框架(如Hibernate或MyBatis)查询数据库,将结果映射到您创建的Java类。

在Spring容器中创建一个bean,该bean将使用步骤2中检索的数据进行初始化。您可以使用@Component注解来标记这个类,这样Spring将自动扫描并创建bean。

如果您需要与数据库保持同步,您需要确保在更新数据库时也更新Spring bean。您可以使用Spring的@Transactional注解来管理事务,并在更新数据库时更新bean。

下面是一个简单的示例代码,说明如何使用Spring JDBC支持查询数据库并将结果注入Spring容器:

java


import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyDatabaseBean {
    private final JdbcTemplate jdbcTemplate;

    public MyDatabaseBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void doSomethingWithDatabase() {
        // Use jdbcTemplate to query the database
        String name = jdbcTemplate.queryForObject("SELECT name FROM users WHERE id = ?", new Object[]{1}, String.class);
        System.out.println("Hello, " + name);
    }
}
Copy code

在上面的示例中,我们使用了Spring的JdbcTemplate类来查询数据库。然后,我们将结果注入到一个名为MyDatabaseBean的Spring bean中。在此示例中,我们只是打印了从数据库检索到的名称,但您可以根据需要执行任何操作。

为了保持与数据库的同步,您应该在更新数据库时更新bean。这可以通过使用@Transactional注解来管理事务并在事务完成时更新bean来完成。例如:

java

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class MyDatabaseBean {
    private final JdbcTemplate jdbcTemplate;
    private String name;

    public MyDatabaseBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
        name = jdbcTemplate.queryForObject("SELECT name FROM users WHERE id = ?", new Object[]{1}, String.class);
    }

    public String getName() {
        return name;
    }

    @Transactional
    public void setName(String newName) {
        jdbcTemplate.update("UPDATE users SET name = ? WHERE id = ?", newName, 1);
        name = newName;
    }
}Copy code

在上面的示例中,我们添加了一个名为setName的方法,该方法用于更新名称。我们使用@Transactional注解来将该方法标记为需要事务管理。在该方法内部,我们首先更新数据库,然后更新bean中的名称属性。由于该方法受事务管理,因此当事务完成时,更新将在数据库中提交,并在bean中反映出来。

  1. test()方法中使用businessDate时,会每天和数据库同步更新吗?
    不会

  2. @Bean private Date businessDate(){}
    这个只是创建个Date 类型的名称为businessDate的bean对象

  3. @Autowired private Date businessDate;
    bean实例化后在属性填充阶段注入其它bean对象,时机:当从IOC获取businessDate的bean时,如果未实例化就执行实例化也就是这个@Bean工厂方法,然后赋值给businessDate,之后这个值不再变

单例模式情况下,在IOC刷新后所有单例都实例化完成,通过@Autowired注入的对象地址不会变,通过@Bean创建的对象也实例化一次。

原型模式:


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TestDemo{

    @Autowired
    private Date businessDate;

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    static Date businessDate(){
        return new Date();
    }

    public void test(){
        System.out.println(businessDate);
    }

}


@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) throws InterruptedException {
        ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class, args);
        context.getBean(Test.class).getTestDemo().test();
 
        context.getBean(Test.class).getTestDemo().test();
    }

    @Component
    static abstract class Test{
        @Lookup
        abstract TestDemo getTestDemo();
    }

}

这种写法是不会每天和数据库同步更新的,只会在系统启动的时候加载一次!
可以使用Spring的@RefreshScope注解来实现实时更新spring容器里的对象属性值。
或者使用 kse_music 提到的原型模式!

思路:定时job去更新bean properties 的值

public class TestDemo implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Bean
    public CustomBean customBean() {
        return new CustomBean(String.valueOf(new Random().nextInt() * 100));
    }

    @PostConstruct
    public void run() {
        new Thread(() -> {
            //可以写成定时任务 去更新
            while (true) {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                CustomBean customBean = applicationContext.getBean(CustomBean.class);
                customBean.setDynamicsValue(String.valueOf(new Random().nextInt()));
                System.out.println(applicationContext.getBean(CustomBean.class).getDynamicsValue());
            }

        }).start();

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public class CustomBean {
        private String dynamicsValue;

        public CustomBean(String dynamicsValue) {
            this.dynamicsValue = dynamicsValue;
        }

        public String getDynamicsValue() {
            return "bean属性随机值:" + dynamicsValue;
        }

        public void setDynamicsValue(String dynamicsValue) {
            this.dynamicsValue = dynamicsValue;
        }
    }

}

img

可以用applicationContext + 定时任务 数据库只要配置对应bean的名称就可以