Spring系列:基于Spring-Jdbc实现事务

文章目录

    • 一、事务基本概念
    • 二、编程式事务
    • 三、声明式事务
      • 前期准备
    • 四、基于注解的声明式事务
      • @Transactional注解标识的位置
      • 事务属性:只读
      • 事务属性:超时
      • 事务属性:回滚策略
      • 事务属性:隔离级别
      • 事务属性:传播行为
      • 测试
    • 五、基于XML的声明式事务

一、事务基本概念

①什么是事务

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

②事务的特性

A:原子性(Atomicity)

一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

C:一致性(Consistency)

事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。

如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。

如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。

I:隔离性(Isolation)

指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。

D:持久性(Durability)

指的是只要事务成功结束,它对数据库所做的更新就必须保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

二、编程式事务

事务功能的相关操作全部通过自己编写代码来实现:

Connection conn = ...;try {// 开启事务:关闭事务的自动提交conn.setAutoCommit(false);// 核心操作// 提交事务conn.commit();}catch(Exception e){// 回滚事务conn.rollBack();}finally{// 释放数据库连接conn.close();}

编程式的实现方式存在缺陷:

  • 细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。
  • 代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。

三、声明式事务

既然事务控制的代码有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。

封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。

  • 好处1:提高开发效率
  • 好处2:消除了冗余的代码
  • 好处3:框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题,进行了健壮性、性能等各个方面的优化

所以,我们可以总结下面两个概念:

  • 编程式自己写代码实现功能
  • 声明式:通过配置框架实现功能

前期准备

①创建表

create database spring;
use  spring;
CREATE TABLE `t_book` (`book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`book_name` varchar(20) DEFAULT NULL COMMENT '图书名称',`price` int(11) DEFAULT NULL COMMENT '价格',`stock` int(10) unsigned DEFAULT NULL COMMENT '库存(无符号)',PRIMARY KEY (`book_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert  into `t_book`(`book_id`,`book_name`,`price`,`stock`) values (1,'斗破苍穹',80,100),(2,'斗罗大陆',50,100);
CREATE TABLE `t_user` (`user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`username` varchar(20) DEFAULT NULL COMMENT '用户名',`balance` int(10) unsigned DEFAULT NULL COMMENT '余额(无符号)',PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
insert  into `t_user`(`user_id`,`username`,`balance`) values (1,'admin',50);

四、基于注解的声明式事务

①搭建子模块

搭建子模块:spring-jdbc-tx

②加入依赖

<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><parent><groupId>com.mcode.spring6</groupId><artifactId>java-spring6</artifactId><version>1.0-SNAPSHOT</version></parent><groupId>com.mcode</groupId><artifactId>java-jdbc-tx</artifactId><packaging>jar</packaging><name>java-jdbc-tx</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><!--spring context依赖--><!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.13</version></dependency><!--spring jdbc  Spring 持久化层支持jar包--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.0.13</version></dependency><!-- 基于xml实现的声明式事务,必须引入aspectJ的依赖,注解声明的事务无需引入 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.13</version></dependency><!-- MySQL驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version></dependency><!-- 数据源 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.19</version></dependency><!--spring对junit的支持相关依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.13</version></dependency><!--junit5测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.3</version></dependency></dependencies>
</project>

③创建jdbc.properties

jdbc.username=root
jdbc.password=123456
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring?characterEncoding=utf8&useSSL=false
jdbc.driverClassName=com.mysql.cj.jdbc.Driver

④创建spring配置类

package com.mcode.tx.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;/*** ClassName: SpringConfig* Package: com.mcode.tx.config* Description:** @Author: robin* @Version: v1.0*/
@Configuration
@ComponentScan("com.mcode.tx")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
public class SpringConfig {@Value("${jdbc.url}")private String url;@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource ds = new DruidDataSource();ds.setUrl(url);ds.setDriverClassName(driverClassName);ds.setUsername(username);ds.setPassword(password);return ds;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}@Beanpublic DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager =new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}
}

⑤创建BookDao接口

package com.mcode.tx.dao;/*** ClassName: BookDao* Package: com.mcode.tx.dao* Description:** @Author: robin* @Version: v1.0*/public interface BookDao {Integer getPriceByBookId(Integer bookId);void updateStock(Integer bookId);void updateBalance(Integer userId,Integer price);
}

⑥创建BookDaoImpl实现类

package com.mcode.tx.dao.impl;import com.mcode.tx.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;/*** ClassName: BookDaoImpl* Package: com.mcode.tx.dao.impl* Description:** @Author: robin* @Version: v1.0*/
@Repository
public class BookDaoImpl implements BookDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic Integer getPriceByBookId(Integer bookId) {String sql = "select price from t_book where book_id=?";Integer price = jdbcTemplate.queryForObject(sql, Integer.class, bookId);return price;}@Overridepublic void updateStock(Integer bookId) {String sql = "update t_book set stock = stock -1 where book_id=?";jdbcTemplate.update(sql, bookId);}@Overridepublic void updateBalance(Integer userId, Integer price) {String sql = "update t_user set balance = balance - ? where user_id=?";//int i = 1 / 0;jdbcTemplate.update(sql, price, userId);}
}

⑦创建BookService接口

package com.mcode.tx.service;/*** ClassName: BookService* Package: com.mcode.tx.service* Description:** @Author: robin* @Version: v1.0*/
public interface BookService {void buyBook(Integer bookId, Integer userId);
}

⑧创建BookService实现类

package com.mcode.tx.service.impl;import com.mcode.tx.dao.BookDao;
import com.mcode.tx.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** ClassName: BookServiceImpl* Package: com.mcode.tx.service.impl* Description:** @Author: robin* @Version: v1.0*/
@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Override@Transactionalpublic void buyBook(Integer bookId, Integer userId) {Integer price = bookDao.getPriceByBookId(bookId);bookDao.updateStock(bookId);bookDao.updateBalance(userId, price);}
}

⑨创建BookController控制器

package com.mcode.tx.controller;import com.mcode.tx.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;/*** ClassName: BookController* Package: com.mcode.tx.controller* Description:** @Author: robin* @Version: v1.0*/
@Controller
public class BookController {@Autowiredprivate BookService bookService;public void buyBook(Integer bookId,Integer userId){bookService.buyBook(bookId, userId);}
}

@Transactional注解标识的位置

@Transactional标识在方法上,则只会影响该方法

@Transactional标识的类上,则会影响类中所有的方法

事务属性:只读

①介绍

对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。

②使用方式

@Transactional(readOnly = true)
public void buyBook(Integer bookId, Integer userId) {//查询图书的价格Integer price = bookDao.getPriceByBookId(bookId);//更新图书的库存bookDao.updateStock(bookId);//更新用户的余额bookDao.updateBalance(userId, price);//System.out.println(1/0);
}

③注意

对增删改操作设置只读会抛出下面异常:

Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

事务属性:超时

①介绍

事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。

概括来说就是一句话:超时回滚,释放资源。

②使用方式

//超时时间单位秒
@Transactional(timeout = 3)
public void buyBook(Integer bookId, Integer userId) {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}//查询图书的价格Integer price = bookDao.getPriceByBookId(bookId);//更新图书的库存bookDao.updateStock(bookId);//更新用户的余额bookDao.updateBalance(userId, price);//System.out.println(1/0);
}

③观察结果

执行过程中抛出异常:

org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Fri Jun 04 16:25:39 CST 2022

事务属性:回滚策略

①介绍

声明式事务默认只针对运行时异常回滚,编译时异常不回滚。

可以通过@Transactional中相关属性设置回滚策略

  • rollbackFor属性:需要设置一个Class类型的对象

  • rollbackForClassName属性:需要设置一个字符串类型的全类名

  • noRollbackFor属性:需要设置一个Class类型的对象

  • rollbackFor属性:需要设置一个字符串类型的全类名

②使用方式

@Transactional(noRollbackFor = ArithmeticException.class)
//@Transactional(noRollbackForClassName = "java.lang.ArithmeticException")
public void buyBook(Integer bookId, Integer userId) {//查询图书的价格Integer price = bookDao.getPriceByBookId(bookId);//更新图书的库存bookDao.updateStock(bookId);//更新用户的余额bookDao.updateBalance(userId, price);System.out.println(1/0);
}

③观察结果

虽然购买图书功能中出现了数学运算异常(ArithmeticException),但是我们设置的回滚策略是,当出现ArithmeticException不发生回滚,因此购买图书的操作正常执行

事务属性:隔离级别

①介绍

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

隔离级别一共有四种:

  • 读未提交:READ UNCOMMITTED

    允许Transaction01读取Transaction02未提交的修改。

  • 读已提交:READ COMMITTED、

    要求Transaction01只能读取Transaction02已提交的修改。

  • 可重复读:REPEATABLE READ

    确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。

  • 串行化:SERIALIZABLE

    确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

各个隔离级别解决并发问题的能力见下表:

隔离级别脏读不可重复读幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

各种数据库产品对事务隔离级别的支持程度:

隔离级别OracleMySQL
READ UNCOMMITTED×
READ COMMITTED√(默认)
REPEATABLE READ×√(默认)
SERIALIZABLE

②使用方式

@Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交
@Transactional(isolation = Isolation.READ_COMMITTED)//读已提交
@Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读
@Transactional(isolation = Isolation.SERIALIZABLE)//串行化

事务属性:传播行为

①介绍

什么是事务的传播行为?

在service类中有a()方法和b()方法,a()方法上有事务,b()方法上也有事务,当a()方法执行过程中调用了b()方法,事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为。

一共有七种传播行为:

  • REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行**【有就加入,没有就不管了】**
  • MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
  • REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】**
  • NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
  • NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
  • NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。】

②测试

创建接口CheckoutService:

package com.mcode.tx.service;/*** ClassName: CheckoutService* Package: com.mcode.tx.service* Description:** @Author: robin* @Version: v1.0*/
public interface CheckoutService {void checkout(Integer[] bookIds, Integer userId);
}

创建实现类CheckoutServiceImpl:

package com.mcode.tx.service.impl;import com.mcode.tx.service.BookService;
import com.mcode.tx.service.CheckoutService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** ClassName: CheckoutServiceImpl* Package: com.mcode.tx.service.impl* Description:** @Author: robin* @Version: v1.0*/
@Service
public class CheckoutServiceImpl implements CheckoutService {@Autowiredprivate BookService bookService;@Override@Transactionalpublic void checkout(Integer[] bookIds, Integer userId) {for (Integer bookId : bookIds) {bookService.buyBook(bookId, userId);}}
}

在BookController中添加方法:

@Autowired
private CheckoutService checkoutService;public void checkout(Integer[] bookIds, Integer userId){checkoutService.checkout(bookIds, userId);
}

在数据库中将用户的余额修改为100元

③观察结果

可以通过@Transactional中的propagation属性设置事务传播行为

修改BookServiceImpl中buyBook()上,注解@Transactional的propagation属性

@Transactional(propagation = Propagation.REQUIRED),默认情况,表示如果当前线程上有已经开启的事务可用,那么就在这个事务中运行。经过观察,购买图书的方法buyBook()在checkout()中被调用,checkout()上有事务注解,因此在此事务中执行。所购买的两本图书的价格为80和50,而用户的余额为100,因此在购买第二本图书时余额不足失败,导致整个checkout()回滚,即只要有一本书买不了,就都买不了

@Transactional(propagation = Propagation.REQUIRES_NEW),表示不管当前线程上是否有已经开启的事务,都要开启新事务。同样的场景,每次购买图书都是在buyBook()的事务中执行,因此第一本图书购买成功,事务结束,第二本图书购买失败,只在第二次的buyBook()中回滚,购买第一本图书不受影响,即能买几本就买几本。

测试

添加TxBoolAnnotationTest类

package com.mcode.tx;import com.mcode.tx.config.SpringConfig;
import com.mcode.tx.controller.BookController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;/*** ClassName: TxBoolAnnotationTest* Package: com.mcode.tx* Description:** @Author: robin* @Version: v1.0*/
@SpringJUnitConfig(SpringConfig.class)
public class TxBoolAnnotationTest {@Autowiredprivate BookController bookController;@Testpublic void testBuyBook() {bookController.buyBook(1, 1);}@Testpublic void testCheckout() {bookController.checkout(new Integer[]{1, 2}, 1);}
}

五、基于XML的声明式事务

添加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"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--    排除SpringConfig配置文件--><context:component-scan base-package="com.mcode.tx"><context:exclude-filter type="assignable" expression="com.mcode.tx.config.SpringConfig"/></context:component-scan><context:property-placeholder location="classpath:jdbc.properties"/><bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"/><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate"><property name="dataSource" ref="druidDataSource"/></bean><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="druidDataSource"/></bean><!--    <tx:annotation-driven transaction-manager="transactionManager"/>--><aop:config><!-- 配置事务通知和切入点表达式 --><aop:advisor advice-ref="txAdvice"pointcut="execution(* com.mcode.tx.service.impl.*.*(..))"/></aop:config><!-- tx:advice标签:配置事务通知 --><!-- id属性:给事务通知标签设置唯一标识,便于引用 --><!-- transaction-manager属性:关联事务管理器 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- tx:method标签:配置具体的事务方法 --><!-- name属性:指定方法名,可以使用星号代表多个字符 --><tx:method name="get*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="find*" read-only="true"/><!-- read-only属性:设置只读属性 --><!-- rollback-for属性:设置回滚的异常 --><!-- no-rollback-for属性:设置不回滚的异常 --><!-- isolation属性:设置事务的隔离级别 --><!-- timeout属性:设置事务的超时属性 --><!-- propagation属性:设置事务的传播行为 --><tx:method name="save*" read-only="false" rollback-for="java.lang.Exception"propagation="REQUIRES_NEW"/><tx:method name="update*" read-only="false" rollback-for="java.lang.Exception"propagation="REQUIRES_NEW"/><tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception"propagation="REQUIRES_NEW"/></tx:attributes></tx:advice>
</beans>

注意:基于xml实现的声明式事务,必须引入aspectJ的依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.13</version>
</dependency>

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

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

相关文章

大数据开发之Sqoop详细介绍

测试环境 CDH 6.3.1 Sqoop 1.4.7 一.Sqoop概述 Apache Sqoop&#xff08;SQL-to-Hadoop&#xff09;项目旨在协助RDBMS与Hadoop之间进行高效的大数据交流。用户可以在 Sqoop 的帮助下&#xff0c;轻松地把关系型数据库的数据导入到 Hadoop 与其相关的系统 (如HBase和Hive)中&…

IRIS、Cache系统类汉化

文章目录 系统类汉化简介标签说明汉化系统包说明效果展示类分类%Library包下的类重点类非重点类弃用类数据类型类工具类 使用说明 系统类汉化 简介 帮助小伙伴更加容易理解后台系统程序方法使用&#xff0c;降低代码的难度。符合本土化中文环境的开发和维护&#xff0c;有助于…

年底大厂今年发多少年终奖,怎么发(上)?

马上就2023年年底了&#xff0c;互联网大厂腾讯员工首先&#xff0c;发年终奖了&#xff0c;111354 元&#xff01; 腾讯的同学可以查一查了&#xff0c;应该发多少已经定下来了&#xff01;&#x1f44b; 除此之外&#xff0c;千寻找了很多的大厂的年终奖发放时间&#xff0c;…

k8s搭建(一、环境配置与docker安装)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

SpringBoot3 整合Redis

1. 场景整合 依赖导入 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>配置 spring.data.redis.host192.168.200.100 spring.data.redis.passwordLfy…

Android Studio 如何隐藏默认标题栏

目录 前言 一、修改清单文件 二、修改代码 三、更多资源 前言 在 Android 应用中&#xff0c;通常会有一个默认的标题栏&#xff0c;用于显示应用的名称和一些操作按钮。但是&#xff0c;在某些情况下&#xff0c;我们可能需要隐藏默认的标题栏&#xff0c;例如自定义标题栏…

时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测

时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测 目录 时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短…

electron + sqlite3 解决打包后无法写入数据库

前言 window环境。 electron28.0.0 sqlite35.1.6 使用 electron-builder 打包。 本文旨在解决打包后无法写入数据库的问题。 但如果你是打包后无法访问sqlite&#xff0c;且有报错弹窗&#xff0c;不妨也看看本文。 也许是同一种原因。 错误原因分析 打包后无法创建db文件&…

【HarmonyOS开发】探究Hap与App包的结构与区别

1、Hap与App包的区别 OpenHarmony 可以进行两种形式&#xff08;Hap和App&#xff09;的打包&#xff0c;HAP是用于本地调试的&#xff0c;APP包是用于上架发布的。 根据不同的设备类型&#xff0c;一个APP包可以包含多个HAP包。 下面从两个角度进行分析 1.1 编译构建角度 编…

uniapp中uview的text组件

基本使用&#xff1a; 通过text参数设置文本内容。推荐您使用:textvalue的形式 <u--text text"我用十年青春,赴你最后之约"></u--text>设置主题&#xff1a; 通过type参数设置文本主题&#xff0c;我们提供了五类属性。primary error success warning…

javafx写一个文档编辑器

文本编辑器是一种用于编辑纯文本文件的工具。它具有基本的文本编辑功能,如插入、删除、复制、粘贴等。文本编辑器通常不具备格式化文本、排版和图形编辑等高级功能,专注于纯文本的编辑。常见的文本编辑器包括记事本(Notepad)、Sublime Text、Visual Studio Code、Atom、Emacs…

【leetcode100-021】【矩阵】搜索二维矩阵 II

【题干】 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 【思路】 以右上角为起点斜着看这个矩阵&#xff0c;会发现&#xff0c;这是一颗二叉搜索树。 …

中间件系列 - Redis入门到实战(高级篇-分布式缓存)

前言 学习视频&#xff1a; 黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 学习目标 Redis持久化Redis主从Redis哨兵Redis分片集群 一 分…

每日一题——LeetCode876.链表的中间结点

个人主页&#xff1a;白日依山璟 专栏&#xff1a;Java|数据结构与算法|每日一题 1.题目描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例1 输入&#xff1a;head [1,2,3,4,5] 输出&…

nginx-proxy-manager初次登录502 bad gateway

nginx-proxy-manager初次登录502 bad gateway 按照官方docker-compose安装后,页面如下: 默认账户密码: adminexample.com/changeme点击sign in,提示Bad Gateway 打开调试 重装后依然如此,最后查阅githup issue 找到答案 https://github.com/NginxProxyManager/nginx-proxy-…

【教学类-43-01】20231226 九宫格数独1.0

作品展示——九宫格数独&#xff08;正方形手工纸&#xff09; 背景需求&#xff1a; 最近陆续出了“X-Y比大小”“X-Y加法判断题”&#xff0c;发现1/3大4班孩子都能完成&#xff0c;3-4位孩子表示“太简单”。 大4班20号同学&#xff0c;做完0-10的判断题后说&#xff1a;“…

OpenHarmony开发者自测试框架初学指南

OH开发者自测试框架初学指南 前言前置环境搭建wsl2安装wsl2迁移源码下载编译环境 测试框架应用环境搭建libreadline-dev安装python库安装nfs-kernel-server验证 windows环境准备vscodeusbipd 生成测试用例更改BUILD.gn的配置项关于fuzz配置编写fuzz用例编译fuzz用例执行 后记 前…

redis在linux集群部署

1.下载redis wget http://download.redis.io/releases/redis-3.2.9.tar.gz 2.解压redis tar -zxvf redis-3.2.9.tar.gz 3.安装redis 在解压redis目录下 make install /usr/soft/redis/ 4.启动redis 在redis的bin目录 执行 ./redis.conf 5.设置redis 端口 密码 集群 vim redis.c…

mongodb聚合_删除_可视化工具

3.5 MongoDB中limit和skip MongoDB Limit() 方法 如果你需要在MongoDB中读取指定数量的数据记录&#xff0c;可以使用MongoDB的Limit方法&#xff0c;limit()方法接受一个数字参数&#xff0c;该参数指定从MongoDB中读取的记录条数。limit()方法基本语法如下所示&#xff1a;…

跟着LearnOpenGL学习12--光照贴图

文章目录 一、前言二、漫反射贴图三、镜面光贴图3.1、采样镜面光贴图 一、前言 在跟着LearnOpenGL学习11–材质中&#xff0c;我们讨论了让每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观&#xf…