01-Spring中事务的实现和事务的属性

news2024/11/26 11:30:20

银行账户转账异常

需求: 实现act-001账户向act-002账户转账10000,要求两个账户的余额一个减成功一个加成功,即执行的两条update语句必须同时成功或失败

实现步骤

第一步: 引入项目所需要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<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>com.powernode</groupId>
    <artifactId>spring6-013-tx-bank</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <!--仓库-->
    <repositories>
        <!--spring里程碑版本的仓库-->
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <!--依赖-->
    <dependencies>
        <!--spring context,关联引入AOP-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--spring jdbc(Spring框架的JdbcTemplate),关联引入了事务相关的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!--德鲁伊连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.13</version>
        </dependency>
       	<!--@Resource注解-->
        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

第二步: 准备t_act表并向表中插入两条账户记录act-001和act-002

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三步: 编写t_act表对应的实体类

@Date
public class Account {
    private String actno;
    private Double balance;
}

第四步: 编写Dao(持久层)中的AccountDao接口及其实现类AccountDaoImpl专门负责t_act表的CRUD操作, 没有任何业务逻辑代码

public interface AccountDao {
    // 根据账号查询余额
    Account selectByActno(String actno);
    // 	更新账户信息
    int update(Account act);
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Override
    public Account selectByActno(String actno) {
        // 根据账号查询账户的信息,并把查询结果封装到对应的实体类中
        String sql = "select actno, balance from t_act where actno = ?";
        Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno);
        return account;
    }

    @Override
    public int update(Account act) {
        // 根据账号更新账户的余额
        String sql = "update t_act set balance = ? where actno = ?";
        int count = jdbcTemplate.update(sql, act.getBalance(), act.getActno());
        return count;
    }
}

第五步: 编写Service(业务层)中的AccountService及其实现类AccountServiceImpl专门负责关于账户的业务逻辑处理,如事务控制的相关代码

public interface AccountService {
    // 转账方法
    void transfer(String fromActno, String toActno, double money);
}
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    // 因为在这个方法中要完成所有的转账业务,所以需要控制事务
    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 如果余额充足开始转账
        Account toAct = accountDao.selectByActno(toActno);
        // 将内存中两个对象的余额先修改
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        
        // 将数据库账户的余额更新
        int count = accountDao.update(fromAct);
        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }
    }
}

第六步: 编写spring的配置文件

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--组件扫描-->
    <context:component-scan base-package="com.powernode.bank"/>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

第七步: 编写测试程序,模拟表示/控制层处理用户的需求,后台调用对应业务层完成业务

public class BankTest {
    @Test
    public void testTransfer(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        try {
            accountService.transfer("act-001", "act-002", 10000);
            System.out.println("转账成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

第八步: 模拟转账异常,如果在更新两个账户余额的操作中出现了异常,此时就会出现前者的余额减了但后者的余额没有加上

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;

    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 余额充足,开始转账
        Account toAct = accountDao.selectByActno(toActno);
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        int count = accountDao.update(fromAct);
        
        // 模拟异常
        String s = null;
        s.toString();

        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }    
    }
}

Spring事务的实现

编程式事务

编程式事务(了解),自己在业务方法中手写控制事务的代码

@Override
public void transfer(String fromActno, String toActno, double money) {
    // 第一步开启事务

    // 第二步执行核心业务逻辑

    // 第三步如果执行核心业务流程中没有异常则提交事务
    
    // 第四步如果执行核心业务流程中有异常则回滚事务
}

声明式事务

声明式事务(常用),基于注解方式XML配置方式实现事务的控制

Spring事务管理的底层是基于AOP实现的,所以Spring专门针对事务开发了一套APIPlatformTransactionManager(事务管理器的核心接口)并且有两个实现类

实现类描述
DataSourceTransactionManager支持JdbcTemplate、MyBatis、Hibernate等事务管理
JtaTransactionManager支持分布式事务管理

第一步: 在spring配置文件中引入tx的命名空间及其约束文件,spring-jdbc依赖中关联了事务相关的依赖

第二步:在spring配置文件中配置事务管理器,如果在Spring6中使用JdbcTemplate就要使用DataSourceTransactionManager事务管理器来管理事务

  • 由于事务管理器DataSourceTransactionManager底层利用的还是Connection连接连接对象开启关闭事务,所以需要给事务管理器配置数据源

第三步: 在spring配置文件中开启事务注解驱动器告诉Spring框架采用注解的方式控制事务

  • 事务管理器就是我们的切面类,@Transactional注解所标识的方法就是连接点(可以织入切面的位置)
<?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.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">  
    <!--组件扫描-->
    <context:component-scan base-package="com.powernode.bank"/>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
     <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--开启事务注解驱动器告诉Spring框架采用注解的方式控制事务-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

第四步: 在Service层中的业务类上或业务方法上添加@Transactional注解,表示当前类/方法开启了事务,业务方法中批量的DML操作可以保证同时成功或失败

  • 在业务类上添加注解: 表示该类中所有的方法都开启事务
  • 在业务方法上添加注解: 表示只有当前方法开启事务
@Service("accountService")
@Transactional// 开启事务
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 余额充足,开始转账
        Account toAct = accountDao.selectByActno(toActno);
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        int count = accountDao.update(fromAct);

        // 模拟异常
        String s = null;
        s.toString();

        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }
    }
}

事务的属性

Transactional注解的源码

public interface Transactional{
    @AliasFor("transactionManager")
    String value() default "";
    @ATiasFor("value")
    String transactionManager() default"";
    String[] label() default {};
    // 事务传播行为
    Propagation propagation() default Propagation.REOUIRED;
    // 事务隔离级别
    Isolation isolation() default Isolation.DEFAULT;
    // 事务超时时间 , 默认-1 , 即没有时间限制
    int timeout() default -1;
    String timeoutString() default "";
    // 只读事务(不能出现增删改的DML语句)
    boolean readOnly() default false;
    // 设置出现哪些异常回滚事务
    class<? extends Throwable>[] rollbackFor() default {};
    String[] rollbackForclassName() default {};
    // 设置出现哪些异常不回滚事务
    class<? extends Throwable>[] noRollbackFor() default {};
    String[] noRolbackForclassName() default {};
}
属性名功能
Propagation(枚举类型)设置事务传播行为
Isolation(枚举类型)设置事务隔离级别
timeout(默认值-1)设置事务超时时间(以最后一条DML语句执行所耗的时间为准) , 默认值是-1表示没有时间限制
readOnly(默认fassle)设置事务是否是只读事务,只读事务内只能出现查询语句,执行DML(增删改)语句时会报错,该特性可以提供查询的效率
rollbackFor设置出现哪些异常后回滚事务
noRollbackFor设置出现哪些异常后不回滚事务

事务传播行为

在XxxService类中的a()方法和b()方法都有事务,若a()方法在执行过程中调用了b()方法,此时就会出现事务传递的行为,所以我们要对这个行为设定一个处理方式

事务传播行为属性Propagation在Spring框架中被定义为枚举类型,一共有七种传播行为

属性值功能
REQUIRED(默认)支持当前所在的事务,如果当前没有开启事务就新建一个
SUPPORTS支持当前所在的事务,如果当前没有开启事务,就以非事务方式执行DML操作
MANDATORY支持当前所在的事务,如果当前没有开启事务将抛出一个异常
REQUIRES_NEW直接开启一个新的事务,如果当前也开启了事务则将当前事务挂起(暂停)
NOT_SUPPORTED支持以非事务方式执行DML操作,如果当前开启了事务则将当前事务挂起(暂停)
NEVER支持以非事务方式执行DML操作,如果当前开启了事务则抛出异常
NESTED如果当前开启了事务,就在当前事务里再嵌套一个完全独立的事务,嵌套的事务可以独立于外层事务进行提交或回滚
如果当前事务不存在,就像REQUIRED一样新建了一个事务,因为嵌套事务的外层事务不存在

实现: 在AccountServiceImpl1中的声明了事务的方法调用AccountServiceImpl2中声明了事务传播行为的方法

第一步: 编写Dao接口及其实现类

public interface AccountDao {
    // 保存账户信息
    int insert(Account act);
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Override
    public int insert(Account act) {
        String sql = "insert into t_act values(?,?)";
        return jdbcTemplate.update(sql, act.getActno(), act.getBalance());
    }

}

第二步: 编写Service接口及其实现类AccountServiceImpl1AccountServiceImpl2,在业务类1中的业务方法调用业务类2中的业务方法

  • REQUIRES: 业务2处于业务1的事务中,即业务1和2在同一个事务中,若2出现了异常需要事务回滚那么1肯定也要回滚(1和2是同一个事务,1捕捉异常也没用)
  • REQUIRES_NEW: 业务类2处于自己的事务中,业务类1的事务会被挂起,若2发生了异常事务肯定回滚,但若1捕捉了2的异常那么1的事务就不会回滚(两个事务)
public interface AccountService {
    // 保存账户信息方法
    void save(Account act);
}
@Service("accountService")
public class AccountServiceImpl1 implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    @Resource(name = "accountService2")
    private AccountService accountService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void save(Account act) {
        // 调用accountDao的insert方法保存act-003账户信息
        accountDao.insert(act); 

        // 创建账户对象
        Account act2 = new Account("act-004", 1000.0);
        // 如果业务类1捕捉到了业务类2的save方法出现的异常,当前事务就不会回滚,因为业务1和业务2就不是同一个事务
        try {
            // 调用AccountServiceImpl2的save方法保存act-004账户信息
            accountService.save(act2); 
        } catch (Exception e) {

        }
        // 业务类1如果捕捉到了业务类2的save方法出现的异常,所以后续的DML操作可以继续执行...........
    }
}
@Service("accountService2")
public class AccountServiceImpl2 implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;

    @Override
    // 直接开启一个新的事务,如果当前也开启了事务则将当前事务挂起(暂停)
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(Account act) {
        // 调用accountDao的insert方法保存act-004账户信息
        accountDao.insert(act);
        // 模拟出现异常,虽然事务还没有结束,但由于出现了异常,当前事务就会回滚那么后续的其他DML语句就无法执行到
        String s = null;
        s.toString();
        // ...............
    }
}

第三步: 集成Log4j2日志框架(引入依赖和配置文件),把警告级别改成DEBUG级别,在日志信息中查看事务对象的创建情况

@Test
public void testPropagation() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    // 获取1号service对象
    AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
    Account act = new Account("act-003", 1000.0);
    accountService.save(act);
}

事务隔离级别

事务隔离级别属性Isolation在Spring框架中被定义为枚举类型,一共四种隔离级别

隔离级别描述脏读不可重复读幻读加锁读
读未提交(理论级别)(READ_UNCOMMITTED)在一个事务中可以看到其他事务未提交的修改数据,大多数的数据库隔离级别都是二档起步不加锁
读已提交 (Oracle默认级别)
(READ_COMMITTED)
在一个事务中只能看到其他事务已经提交的修改数据,这种隔离级别每次读到的都是真实数据不加锁
可重复读(MySQL默认级别)
(REPEATABLE_READ)
一个事务中多次执行相同的SELECT语句得到的是相同的结果,永远读取的都是自己刚开启事务时的数据,不管其他事务是否提交了修改数据不加锁
序列化(最高隔离级别)
SERIALIZABLE
一个事务与其他事务完全地隔离,每一次读取到的数据都是最真实的,但是所有事务只能排队执行,不支持并发所以效率最低加锁

第一步: 编写dao层接口及其实现类

public interface AccountDao {
    // 根据账号查询账户信息
    Account selectByActno(String actno);
    // 保存账户信息
    int insert(Account act);
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Override
    public Account selectByActno(String actno) {
        String sql = "select actno, balance from t_act where actno = ?";
        Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno);
        return account;
    }

    @Override
    public int insert(Account act) {
        String sql = "insert into t_act values(?,?)";
        return jdbcTemplate.update(sql, act.getActno(), act.getBalance());
    }
}

第二步: 编写Service层接口及其实现类IsolationService1IsolationService2,业务类1负责查询账户,业务类2负责插入账户同时模拟延迟

  • READ_UNCOMMITTED: 表示当前事务可以读取到其他的事务没有提交的数据,没有提交就代表事务可能回滚将来数据可能不存在
  • READ_COMMITTED: 在一个事务中只能看到其他事务已经提交的修改数据读不到则报异常,这种隔离级别每次读到的都是真实数据
public interface AccountService {
    // 根据账号查询账户信息
    void getByActno(String actno);
    // 保存账户信息方法
    void save(Account act);
}         
@Service("i1")
public class IsolationService1 {
    @Resource(name = "accountDao")
    private AccountDao accountDao;

    // 当前事务可以读取到其他事务没有提交的数据
    //@Transactional(isolation = Isolation.READ_UNCOMMITTED)
    // 当前事务只能看到其他事务已经提交的修改数据读不到则报异常
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void getByActno(String actno) {
        Account account = accountDao.selectByActno(actno);
        System.out.println("查询到的账户信息:" + account);
    }
}
@Service("i2")
public class IsolationService2 {
    @Resource(name = "accountDao")
    private AccountDao accountDao;

    @Transactional
    public void save(Account act) {
        accountDao.insert(act);
        // 睡眠一会让当前事务晚点提交,在睡眠期间看其他事务能否查到当前事务未提交的数据
        try {
            Thread.sleep(1000 * 20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试先执行业务类2的save方法保存一条账户数据,然后看业务类1中是否能查询到业务类2保存的账户信息

// 先调用业务类2的save方法先保存一条账户数据
@Test
public void testIsolation2(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    IsolationService2 i2 = applicationContext.getBean("i2", IsolationService2.class);
    Account act = new Account("act-004", 1000.0);
    i2.save(act);
}
// 在业务类2的save方法事务还没有提交的期间内,查看业务类2保存的账户信息
@Test
public void testIsolation1(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    IsolationService1 i1 = applicationContext.getBean("i1", IsolationService1.class);
    i1.getByActno("act-004");
}

事务超时

设置事务的超时时间后(默认没有时间限制),当如果该事务中执行最后一条DML语句时一共所耗的时间已经超过了规定的时间事务会选择回滚

//  -1是默认值,表示执行事务没有时间限制
@Transactional(timeout = -1)
// 表示超过10秒如果该事务中所有的DML语句还没有执行完毕的话事务会选择回滚
@Transactional(timeout = 10)

事务的超时时间是指执行最后一条DML语句时一共所耗的时间,最后一条DML语句后面的业务代码执行所耗的时间不会被计入超时时间内

@Transactional(timeout = 10) // 设置事务超时时间为10秒。
public void save(Account act) {
    accountDao.insert(act);
    // 这段睡眠时间是不会被计入事务的超时时间内的
    try {
        Thread.sleep(1000 * 15);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

如果想让整个方法的所有代码都计入超时时间的话,可以在方法最后一行添加一行无关紧要的DML语句

@Transactional(timeout = 10) // 设置事务超时时间为10秒。
public void save(Account act) {
    // 这段睡眠时间是会被计入事务的超时时间内的
    try {
        Thread.sleep(1000 * 15);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
    // 该DML语句之前执行所耗的时间也会被计入事务的超时时间内
    accountDao.insert(act);
}

只读事务

只读事务表示在当前事务执行过程中只允许select语句执行,执行DML(增删改)语句时会报错

  • 虽然执行select语句可以不用加事务控制,但若该事务中确实没有增删改操作设置为只读事务后可以启动Spring的优化策略从而提高select语句的执行效率
// 将当前事务设置为只读事务,默认值为false
@Transactional(readOnly = true)

异常回滚事务

设置只有发生Xxx异常该异常的子类异常时事务才会回滚,发生其他异常时事务都不会回滚

// 只有发生RuntimeException异常或该异常的子类异常时事务才会回滚
@Transactional(rollbackFor = RuntimeException.class)

异常不回滚事务

设置只有发生Xxx异常该异常的子类异常时事务才不回滚,发生其他异常时事务都会回滚

// 只有发生NullPointerException异常或该异常的子类异常时事务才不回滚
@Transactional(noRollbackFor = NullPointerException.class)

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

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

相关文章

LeetCode | 206. 反转链表

LeetCode | 206. 反转链表 OJ链接 这里有两个思路 我们先来看第一个思路&#xff1a; 创建一个新的链表&#xff0c;然后将原链表头插头插需要保存下一个的地址&#xff0c;再头插 代码如下&#xff1a; struct ListNode* reverseList(struct ListNode* head) {struct ListN…

利用机器学习的力量来对抗野火

一、介绍 野火因其对环境、经济和社会的破坏性影响而成为日益紧迫的全球关注点。近年来&#xff0c;野火的频率和强度显著上升&#xff0c;气候变化和土地管理实践等因素加剧了野火。解决这一危机需要创新和多方面的方法&#xff0c;一个有前途的途径是将机器学习整合到野火管理…

Hugging Face高效训练技术一:单 GPU 高效训练

文章目录 一、模型训练1.1 准备测试数据1.2 加载模型1.3 默认配置训练的显存占用1.4 Model’s Operations1.5 Model’s Memory 二、梯度累积&#xff08;Gradient Accumulation&#xff09;2.1 批量大小2.2 梯度累积 三、梯度检查点&#xff08;Gradient Checkpointing&#xf…

8年经验的老程序员,告诉你如何看透面试、通过面试

关注公众号程序员小灰&#xff0c;不迷路&#xff01; 大家好&#xff0c;我是程序员小灰。小灰的公众号里有一位读者朋友鹤涵&#xff0c;是一个8年Java经验的资深程序员&#xff0c;并且当过多年面试官&#xff0c;面试过的人数超过百人。 今天&#xff0c;小灰特意把他邀请过…

优雅设计之美:实现Vue应用程序的时尚布局

前言 页面布局是减少代码重复和创建可维护且具有专业外观的应用程序的基本模式。如果使用的是Nuxt&#xff0c;则可以提供开箱即用的优雅解决方案。然而&#xff0c;令人遗憾的是&#xff0c;在Vue中&#xff0c;这些问题并未得到官方文档的解决。 经过多次尝试&#xff0c;小…

C# Onnx Dense Face 3D人脸重建,人脸Mesh

效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms;namespace Onnx_Demo {public partial class frmMain : Form{public frmMain(){InitializeComponent();}string fileFilter "*.…

随笔--解决ubuntu虚拟环境的依赖问题

文章目录 问题一&#xff1a;在conda虚拟环境中报错ImportError: libcupti.so.11.7:cannot open shared object file: No such file or directory解决步骤问题二&#xff1a; RuntimeError: CUDA error: CUBLAS_STATUS_INVALID_VALUE when calling cublasSgemmStridedBatched( …

打造高效运营底座,极智嘉一体化软件系统彰显科技威能

在仓储成本和物流需求日益增加的今天&#xff0c;创新且高效的物流机器人解决方案能够显著提升物流运营效率&#xff0c;降低物流成本&#xff0c;实现智能化、精益化、一体化的物流管理。全球仓储机器人引领者极智嘉(Geek)以「一套系统&#xff0c;天生全能」为准则&#xff0…

python 虚拟环境使用

创建虚拟环境 python -m -venv dir dir是要创建虚拟环境的目录,文件夹不存在会自动创建相关的文件夹及其父文件夹. 示例 python -m venv d:\pythonvenv\python3.11.5 这样会在d:\pythonvenv\python3.11.5 目录下创建一个虚拟环境 使用帮助: python -m -venv -h 使用虚拟…

2023下半年软考系统集成项目管理工程师上午真题及答案解析

1.( C )不属于风险识别的信息收集技术。 A.头脑风暴 B.德尔菲技术 C.排除法 D.根本原因分析 解析&#xff1a; 2.( C )不是SaaS(软件即服务)的特点。 A.由供应商管理软件更新和安全 B.无需购买软件 C.需要自行安装和维护软件 D.按需付费 解析&#xff1a; 3.…

蓝牙芯片的 PCB 板载天线设计注意事项

1.天线示意图 1.1 要点说明 ⑴ 板厚不同&#xff0c;适用的天线不同 ⑵ PIFA天线到地的距离不要变&#xff08;很重要&#xff09;&#xff0c;通常在PCB设计时要锁定参考设计复制/拷贝比较好。 ⑶ ANT 馈线需要符合50 欧阻抗&#xff0c;背面需铺铜&#xff0c;板厚、粗细、与…

【编码魔法师系列_构建型2.2】单例模式「懒汉式」(Singleton Pattern)

学会设计模式&#xff0c;你就可以像拥有魔法一样&#xff0c;在开发过程中解决一些复杂的问题。设计模式是由经验丰富的开发者们&#xff08;GoF&#xff09;凝聚出来的最佳实践&#xff0c;可以提高代码的可读性、可维护性和可重用性&#xff0c;从而让我们的开发效率更高。通…

如何整合项目计划与执行,看看这篇就够了

项目中的挑战&#xff0c;如同生活中的问题&#xff0c;无处不在。常言道&#xff1a;“家家有本难念的经”&#xff0c;面对这些问题&#xff0c;我们应采取积极的态度&#xff0c;通过有效的沟通&#xff0c;让家人了解我们的困境&#xff0c;这样许多问题就能在无形中得到解…

虚拟机Linux-Centos系统网络配置常用命令+Docker 的常用命令

目录 1、虚拟机Linux-Centos系统网络配置常用命令2、Docker 的常用命令2.1 安装docker步骤命令2.2 在docker容器中安装和运行mysql 1、虚拟机Linux-Centos系统网络配置常用命令 进入网络配置文件目录 cd /etc/sysconfig/network-scripts/用 ls 命令查看文件&#xff1a;ls …

基于SpringAOP实现自定义接口权限控制

文章目录 一、接口鉴权方案分析1、接口鉴权方案2、角色分配权限树 二、编码实战1、定义权限树与常用方法2、自定义AOP注解3、AOP切面类&#xff08;也可以用拦截器实现&#xff09;4、测试一下 一、接口鉴权方案分析 1、接口鉴权方案 目前大部分接口鉴权方案&#xff0c;一般…

Ps:色域警告

Ps菜单&#xff1a;视图/色域警告 View/Gamut Warning 色域警告 Gamut Warning可以依据要模拟的输出设备的色彩能力来确定图像上的哪些颜色可能会超出该设备的色彩范围。 “色域警告”只能起到提示的作用&#xff0c;启用&#xff08;勾选&#xff09;以后&#xff0c;画面上的…

清华软院2024届推免拟录取名单

名单 直博生 硕士生 分析 清华软院2024届共录取推免硕士生68人&#xff0c;其中 专硕085405软件工程 59人&#xff0c;学硕083500软件工程9人&#xff1b;推免直博生 15人 和贵系相比难度要低很多哦&#xff01; 欢迎关注我的公众号 “程序员小风学长”&#xff0c;会定期进…

【工具】Github统计代码行数工具推荐(VScode插件、兼容任何平台、不用下载安装包)

需求&#xff1a; 1&#xff09;被要求统计代码行数&#xff1b; 2&#xff09;不想打开Linux&#xff0c;懒得下载Windows版本GitStats&#xff1b; 3&#xff09;打开了Linux但也不记得find命令行怎么用&#xff1b; 4&#xff09;打开了Linux&#xff0c;装好了Gitstats但自…

基于金枪鱼群算法的无人机航迹规划-附代码

基于金枪鱼群算法的无人机航迹规划 文章目录 基于金枪鱼群算法的无人机航迹规划1.金枪鱼群搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用金枪鱼群算法来优化无人机航迹规划。 …

唐顿庄园的AI圣诞设计(ideogram.ai )

唐顿庄园是一部经典的英国历史剧&#xff0c;讲述了 Crawley 家族在 20 世纪初生活的故事。该剧以其精美的服装、场景和道具而闻名&#xff0c;因此它是圣诞装饰的绝佳灵感。 在本文中&#xff0c;我们将使用 ideogram.ai 创建一个 Downton Abbey 圣诞设计。ideogram.ai 是一个…