十大网站建设排名,毕业设计 网站开发简单吗,互联网代理,北京seo软件单点登录 1.配置代理信息 /*请求登陆的方法*/
/modelLogin: {//本地服务接口地址#xff0c;这是测试环境#xff0c;正式环境需要更改下地址target: http://127.0.0.1:6776/xxx-auth/,changeOrigin: true,pathRewrite: {^/modelLogin: … 单点登录 1.配置代理信息 /*请求登陆的方法*/
/modelLogin: {//本地服务接口地址这是测试环境正式环境需要更改下地址target: http://127.0.0.1:6776/xxx-auth/,changeOrigin: true,pathRewrite: {^/modelLogin: ,},
},//异步进行登录
this.$store.dispatch(LoginPrammeSystem, loginForm).then(() {//跳转到指定连接正式环境需要更改地址window.open(http://localhost:1889/);
}); image.png image.png image.png image.png image.png MySQL对于千万级的大表如何优化 优化你的sql、索引 B树 sql优化 避免多表联合查询优化难度大 设置合理的查询字段避免多次回表 索引 建立合适的索引 避免索引失效 优点 解决读的性能瓶颈 缺点 缓存数据库一致性 缓存穿透 缓存雪崩 缓存击穿 架构复杂高可用 客户端直接连接 客户端直连方案因为少了一层 proxy 转发所以查询性能稍微好一点儿并且整体架构简单排查问题更方便。但是这种方案由于要了解后端部署细节所以在出现主备切换、库迁移等操作的时候客户端都会感知到并且需要调整数据库连接信息。中间件ShardingSphere 带proxy 带 proxy 的架构对客户端比较友好。客户端不需要关注后端细节连接维护、后端信息维护等工作都是由 proxy 完成的。但这样的话对后端维护团队的要求会更高。而且proxy 也需要有高可用架构。因此带 proxy 架构的整体就相对比较复杂。中间件ShardingSphere 、Atlas 、mycat 优点 分担主库的压力 缺点 从延迟导致往主库写入的数据跟从库读出来的数据不一致 优点 优化单一表数据量过大而产生的性能问题 避免IO争抢并减少锁表的几率 缺点 主键避免重复分布式Id 跨节点分页、排序函数 数据多次扩展难度跟维护量极大 image.png image.png image.png image.png image.png mac安装Elasticsearch 使用的是2.3.2版本 下载的是tar版本的然后解压。 cd elasticsearch-2.3.2 bin/elasticsearch 这时可能会报一个logs文件夹权限问题的错误 sudo chown -R dalaoHang logs 重启es 在页面访问http://localhost:9200/ 安装一个可视化插件elasticsearch-head sudo bin/plugin install mobz/elasticsearch-head 安装成功后重启es访问http://localhost:9200/_plugin/head/ Linux文件结构与文件权限 d:代表当前文件为文件夹 l:代表当前文件为超连接文件 b:该文件提供为提供给系统存取的设备例如你计算机的硬盘所存储的数据内容可能都会保存在这个类型文件中 c:代表着连接到你计算机的一些硬件设备例如鼠标、键盘等配置文件开头都是以c开头的 一个b打头的文件这个文件是提供系统存储的数据且可能硬盘也可能是其他存储设备的 ll /dev/sda c打头的文件则是硬件设备 而c打头的文件则是硬件设备我们不妨键入 ll /dev查看一下 BUS总线以及CPU等这些都是硬件设备 在Linux中隐藏文件大多以.开头 ls -al查看 1. /:根目录与开机系统有关
2. /usr(unix software resource):与软件的安装和执行有关
3. /var(variable):与系统的运作有关 根目录下有个bin文件夹我们日常使用Linux的时候都会用到ls、cat、touch、mkdir等基本操作命令都存放于bin目录下 接下来是/boot这个目录存放的基本都是Linux开机会用到配置文件像Linux kerner常用到的文件名 vmlinuz就会存放在这个文件夹下 接下来是/dev这个文件夹基本存放的都是硬件设备我们都知道Linux主张一切皆文件所以所有的鼠标、键盘、硬盘的设备信息都是存放在这个文件夹下 /etc目录则是存放配置文件的地方常见我们的用户文件/etc/passwd以及密码文件/etc/shadow还有系统文件/etc/rc等都会存放在这个目录下。 mnt存放挂载相关。 lib存放库函数相关、 sbin存放开机、系统还原、修复等众多指令。 tmp存储临时文件习惯。 /usr/lib与根目录的lib功能相同存放的基本是lib目录下的软链接。 /usr/local/则是FHS希望用户将下载的软件都放到这个目录下统一管理 /usr/sbin同样也是将根目录的sbin目录下的指令软链接到此。 /var/lock存放的则是被某个程序锁定的文件已确保其他程序不会同时使用到这个文件 /var/lib存放的则是会临时改变的库文件 文件权限 r代表读权限。 w代表写权限。 x代表执行权限。 # 进入tmp目录cd /tmp/# 创建testDir文件夹
mkdir testDir# 设置这个文件夹 所属者有所有权限 所属组和其他用户只有读和写权限
chmod 766 testDir/ MySQL 并不是跳过 OFFSET 行而是取 OFFSETN 行然后放弃前 OFFSET 行最后返回 N 行当 OFFSET 特别大的时候效率就非常的低下 spring security支持的oauth resource server自带BearerTokenAuthenticationFilter去校验jwt所以简单配置一个jwtDecoder就可以实现完全相同的功能 整合SpringSecurity和JWT实现登录认证和授权 SpringSecurity是一个强大的可高度定制的认证和授权框架对于Spring应用来说它是一套Web安全标准。SpringSecurity注重于为Java应用提供认证和授权功能像所有的Spring项目一样它对自定义需求具有强大的扩展性。 其核心就是一组过滤器链在spring security中一种过滤器处理一种认证方式项目启动后将会自动配置 JWT是JSON WEB TOKEN的缩写它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象由于使用了数字签名所以是可信任和安全的。总结来说JWT只是一个生成token的机制。 JWT的组成 JWT token的格式header.payload.signature 可以在该网站上获得解析结果jwt.io/ header中用于存放签名的生成算法 payload中用于存放用户名、token的生成时间和过期时间 signature为以header和payload生成的签名一旦header和payload被篡改验证将失败 JWT实现认证和授权的原理 用户调用登录接口登录成功后获取到JWT的token 之后用户每次调用接口都在http的header中添加一个叫Authorization的头值为JWT的token 后台程序通过对Authorization头中信息的解码及数字签名校验来获取其中的用户信息从而实现认证和授权。 !--SpringSecurity依赖配置--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependency
!--JWT(Json Web Token)登录支持--
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.0/version
/dependency jwt:tokenHeader: X-Token #JWT存储的请求头tokenHead: Bearer #令牌前缀secret: xx-admin-secret #JWT加解密使用的密钥expiration: 604800 #JWT的超期限时间秒(60*60*24) Slf4j
Component
public class JwtTokenUtil {private static final String CLAIM_KEY_USERNAME sub;private static final String CLAIM_KEY_CREATED created;Value(${jwt.secret})private String secret;Value(${jwt.expiration})private Long expire;/*** 从token中获取登录用户名*/public String getUserNameFromToken(String token) {String username;try {Claims claims getClaimsFromToken(token);username claims.getSubject();} catch (Exception e) {username null;}return username;}/*** 校验token*/public boolean validateToken(String token, UserDetails userDetails) {String username getUserNameFromToken(token);return username.equals(userDetails.getUsername()) !isTokenExpired(token);}/*** 根据用户信息生成token*/public String generateToken(UserDetails userDetails) {MapString, Object claims new HashMap();claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 判断token是否已经失效*/private boolean isTokenExpired(String token) {Date expiredDate getClaimsFromToken(token).getExpiration();return expiredDate.before(new Date());}private String generateToken(MapString, Object claims) {return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate())//签名算法.signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 生成token的过期时间*/private Date generateExpirationDate() {return new Date(System.currentTimeMillis() expire * 1000);}private Claims getClaimsFromToken(String token) {Claims claims null;try {claims Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {log.info(JWT格式验证失败:{},token);}return claims;}
} Configuration
EnableWebSecurity
EnableGlobalMethodSecurity(prePostEnabledtrue)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {Autowiredprivate CustomAccessDeniedHandler customAccessDeniedHandler;Autowiredprivate CustomAuthenticationEntryPoint customAuthenticationEntryPoint;Autowiredprivate XlUserService xlUserService;Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity.csrf().disable()// 由于使用的是JWT我们这里不需要csrf.sessionManagement()// 基于token所以不需要session.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 允许对于网站静态资源的无授权访问.antMatchers(HttpMethod.GET,/,/*.html,/favicon.ico,/**/*.html,/**/*.css,/**/*.js,/swagger-resources/**,/v2/api-docs/**).permitAll()// 对登录注册要允许匿名访问.antMatchers(/ucenter/xl-user/login, /ucenter/xl-user/register).permitAll()//跨域请求会先进行一次options请求.antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest()// 除上面外的所有请求全部需要鉴权认证.authenticated();// 禁用缓存httpSecurity.headers().cacheControl();// 添加JWT filterhttpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);//添加自定义未授权和未登录结果返回httpSecurity.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler).authenticationEntryPoint(customAuthenticationEntryPoint);}Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}BeanOverridepublic UserDetailsService userDetailsService() {//获取登录用户信息return username - {XlUser user xlUserService.getUserByCode(username);if (user ! null) {ListXlResource permissionList xlUserService.getResourceList(user.getUserId());return new JwtUser(user,permissionList);}throw new UsernameNotFoundException(用户名或密码错误);};}/*** 装载BCrypt密码编码器*/Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}/*** JWT filter*/Beanpublic JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){return new JwtAuthenticationTokenFilter();}
} 编写service实现 Slf4j
Service
public class XlUserServiceImpl extends ServiceImplXlUserMapper, XlUser implements XlUserService {Autowiredprivate PasswordEncoder passwordEncoder;Autowiredprivate UserDetailsService userDetailsService;Autowiredprivate JwtTokenUtil jwtTokenUtil;Overridepublic XlUser register(XlUser user) {XlUser newXlUser new XlUser();BeanUtils.copyProperties(user, newXlUser);//查询是否有相同用户名的用户ListXlUser xlUsers this.baseMapper.selectList(new LambdaQueryWrapperXlUser().eq(XlUser::getUserCode,newXlUser.getUserCode()));if (CollectionUtil.isNotEmpty(xlUsers)) {return null;}//将密码进行加密操作String encodePassword passwordEncoder.encode(user.getPassWord());newXlUser.setPassWord(encodePassword);this.baseMapper.insert(newXlUser);return newXlUser;}Overridepublic String login(String username, String password) {String token null;try {UserDetails userDetails userDetailsService.loadUserByUsername(username);if (!passwordEncoder.matches(password, userDetails.getPassword())) {throw new BadCredentialsException(密码不正确);}UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication);token jwtTokenUtil.generateToken(userDetails);} catch (AuthenticationException e) {log.warn(登录异常:{}, e.getMessage());}return token;}Overridepublic ListXlResource getResourceList(Long userId) {return this.baseMapper.getResourceList(userId);} 测试访问需要权限的接口 PreAuthorize(hasAuthority(read))
ApiOperation(获取用户所有可访问的资源) image.png mysql优化 | 存储引擎建表索引sql的优化建议 存储引擎 mysql中查看支持的引擎的sql show engines; 日常工作中使用较多的存储引擎对比InnoDBMyISAM InnoDB 存储限制 64T 支持事务 支持索引 支持数据缓存 支持外键 MyISAM 存储限制 256T 支持索引 支持全文索引 从MySQL5.6版本开始InnoDB已经支持创建全文索引了 innodb 支持提交、回滚和崩溃恢复能力的事物安全ACID支持行锁支持外键完整性约束 适合场景 需要事务处理 表数据量大高并发操作 MyISAM MyISAM存储引擎提供了高速检索和存储的能力支持全文索引 适合场景 很多count计算的 查询非常频繁的 建表原则 在建表的时候尽量遵循以下原则 尽量选择小的数据类型数据类型选择上尽量tinyint(1字节)smallint(2字节)int(4字节)bigint(8字节)比如逻辑删除yn字段上1代表可用0代表就可以选择tinyint1字节类型 尽量保证字段数据类型长度固定 尽量避免使用null使用null的字段查询很难优化影响索引可以使用0或代替 避免宽表能拆分就拆分一个表往往跟一个实体域对应就像设计对象的时候一样保持单一原则 尽量避免使用text和blob如果非使用不可将类型为text和blob的字段在独立成一张新表然后使用主键对应原表 禁止使用float或double类型这个坑超大float或double存在精度问题在进行比较或者加减操作的时候会丢失精度导致数据异常凡是使用float或double类型的时候考虑下可不可使用int或bigint代替。比如金额以元为单位使用float或double类型的时候可以考虑以分为单位使用intbigint类型代替然后由业务代码进行单位的转换。 每张表都加上createUser,createTime.updateUser,updateTime字段 起名字要规范包括库名表名字段名索引名 查询频繁使用的字段记得加索引 尽量避免使用外键不用外键约束性能更高然后数据的完整性有程序进行管理 如果表的数量可以预测到非常大最好在建表的时候就进行分表不至于一时间数据量非常大导致效率问题 索引 索引是为来加速对表中数据行中的检索而创建的一种分散的数据结果,是针对表而建立的它是由数据页面以外的索引页面组成,每个索引页中的行都含有逻辑指针,以便加速检索物理数据创建索引的目的在于提高查询效率innodb的索引都是基于b tree实现的 索引类型 普通索引最基本的索引无限制 //1
create index idx_username on sys_user(user_name(32));// 2
alter table sys_user add index idx_username(user_name(32)); 主键索引一个表只能有一个主键索引且不能为空 一般建表时同时创建了主键索引 create table sys_user (id int(11) not null auto_increment,user_name varchar(32) default null,pass_word varchar(32) default null,token varchar(32) default null,yn smalliint(6) default null,primary key (id)
) engineInnoDB auto_increment348007 default charsetutf8; 唯一索引与普通索引类似不同的就是索引列的值必须唯一但允许有空值。如果是组合索引则列值的组合必须唯一 CREATE UNIQUE INDEX idx_token ON sys_user(token_expire) 组合索引指多个字段上创建的索引只有在查询条件中使用了创建索引时的第一个字段索引才会被使用。使用组合索引时遵循最左前缀集合 alter table sys_user add index idx_un_te (user_name(32), token_expire); 全文索引用来查找文本中的关键字而不是直接与索引中的值相比较。只有char、varchartext 列上可以创建全文索引 CREATE FULLTEXT INDEX idx_ ON sys_user(pass_word) 总之使用索引的时候需要考虑的地方比较多但是归根结底就是查询尽量走索引走索引尽量避免回表或减少回表次数 创建使用索引的原则 索引的字段尽量要小根据索引查询数据的快慢取决于b tree的高度当数据量恒定的时候字节越少存的索引的数量就越多树的高度就越会越低 比如设置varchar(10)则这个索引建立的时候只会存字段前10个字节字段设置的字节数比较小可能会导致索引查出来的数据多进而进行回表导致性能下降所以字段设置为多少还是要自己斟酌一下 遵循索引的最左匹配原则 注意使用like的时候尽量不要使用“%a%”这样的不走索引可以使用“a%”走索引 不要在索引的列上进行计算比如 select * from sys_user where token_expire1 10000这样的语句 不会走有索引 什么样的字段建索引就是那种频繁在wheregroup byorder by中出现的列最好加上索引 使用联合索引的时候尽量考虑到索引下推优化 对于使用or的条件需要or左右的条件都是索引才会走索引否则走全表扫描可以考虑使用union代替 避免使用select *对于只需要查询主键或者where 条件中只有索引的字段 这时会走覆盖索引建少回表次数 sql语句中避免隐式转换在MySQL中字符串和数字做比较的话是将字符串转换成数字如字段是varchar类型但是入参是int类型即便字段有索引也不会走因为这里会进行一次隐式转换 索引的缺点 虽然索引的可以提高查询的效率但是在进行insertupdate和delete的时候会降低效率因为在保存数据的同时也会去保存索引。 不要在一个表里建过多的索引问题跟上面一样在操作数据的时候效率降低而且数据量少的表要看情况建索引如果建索引跟没建索引的效果差不多少的情况下就不要建索引了如果是数据量大的表就需要建索引去优化查询效率。 explain分析sql 可以使用explain去分析sql的执行情况比如 explain select * from sys_user where token_expire 10000; 在阿里的开发手册中提到过sql性能优化的标准至少要达到range要求ref级别如果可以是consts最好 consts 是指单表中最多只有一个匹配行主键或唯一索引 ref 指的是使用普通索引 range 是指对索引进行范围查询 sql优化 关于sql语句的优化主要是两方面一个是在建sql的时候需要注意的问题另一个就是在发现有慢sql的时候可以根据不同情况进行分析然后优化sql 现在innodb已经支持全文索引了 从MySQL5.6版本开始InnoDB支持创建全文索引 优化的建议 查询的时候一定要记得使用limit进行限制 对于结果只需要一条数据的查询用limit 1进行限制 使用count(*)或count(1)来统计行数来查询使用count(列)的时候需要在查看列中这个是否为null,不会统计此列为null的情况而且mysql已经对count(*)做了优化 不要使用select * 来查数据使用select 需要的列名这样的方式去查询 使用join链接代替子查询 不要使用外键外键的约束可以放在程序里解决 控制一下in操作的集合数量不要太大了 针对慢查询使用explain去分析原因然后优化sql让其尽量走索引 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png spring boot集成mqtt协议发送和订阅数据 Autowired
private MqttGatewayComponent mqttGatewayComponent;//发送字符串或json字符串,到指定的topic
mqttGatewayComponent.sendToMqtt(json string, data/abcd);/*** desc MQTT发送网关*/
Component
MessagingGateway(defaultRequestChannel mqttOutboundChannel)
public interface MqttGatewayComponent {void sendToMqtt(String data);void sendToMqtt(String payload, Header(MqttHeaders.TOPIC) String topic);void sendToMqtt(Header(MqttHeaders.TOPIC) String topic, Header(MqttHeaders.QOS) int qos, String payload);}// 通过通道获取数据 订阅的数据
// 配置监听的 topic 支持通配符
// 发送通道配置 默认主题Bean
public MqttConnectOptions getMqttConnectOptions(){// MQTT的连接设置MqttConnectOptions mqttConnectOptions new MqttConnectOptions();// 设置连接的用户名mqttConnectOptions.setUserName(username);// 设置连接的密码mqttConnectOptions.setPassword(password.toCharArray());// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录// 把配置里的 cleanSession 设为false客户端掉线后 服务器端不会清除session// 当重连后可以接收之前订阅主题的消息。当客户端上线后会接受到它离线的这段时间的消息mqttConnectOptions.setCleanSession(true);// 设置发布端地址,多个用逗号分隔, 如:tcp://111:1883,tcp://222:1883// 当第一个111连接上后,222不会在连,如果111挂掉后,重试连111几次失败后,会自动去连接222mqttConnectOptions.setServerURIs(hostUrl.split(,));// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线但这个方法并没有重连的机制mqttConnectOptions.setKeepAliveInterval(20);mqttConnectOptions.setAutomaticReconnect(true);// 设置“遗嘱”消息的话题若客户端与服务器之间的连接意外中断服务器将发布客户端的“遗嘱”消息。mqttConnectOptions.setWill(willTopic, willContent.getBytes(), 2, false);mqttConnectOptions.setMaxInflight(1000000);return mqttConnectOptions;
} 说明由于测试机的端口限制,单机最多也就65553个端口了所以理论上jmeter最大也就可以模拟6万个连接系统本身也会有很多服务占用端口 使用虚拟机理论上是可以让测试机端口无限的前提性能跟得上。但实际中我们发现单台测试机跑jmeter到3万个连接其实已经是极限了内存和cpu性能问题 netty的大型响应式分布式物联网智能家电系统,十万长连接 压测效果 单机下压测效果 稳定6万连接自身配置限制 i5 6300hq16G 压测效果 集群模式下两节点压测效果 达成12万连接 image.png 不想再用AOP收集业务操作日志 业务操作日志是软件系统中用于记录和跟踪用户对业务数据执行的操作的日志。这些日志提供了对系统活动的见解有助于审计、监控、分析和重构业务流程。 作为一名对Spring重度使用者基于上面的需求目标马上想到了基于AOP切面注解的传统方案AOP切面和注解来设计业务操作日志是一种非常自然和高效的方法我们基于AOP切面和注解的方法来实现我们系统中的业务操作日志记录这种方案允许我们以最小的侵入性来捕获核心业务操作并在执行前后自动记录相关数据。通过定义注解我们可以轻松地标记那些需要记录日志的业务方法。 1.1 定义日志注解 首先你需要定义一个或多个注解用于标记哪些方法需要记录业务操作日志。 Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface Loggable {String value() default ;// 可以添加更多的配置属性如操作类型、级别等
} 1.2 创建AOP切面 接下来创建一个切面类来处理带有Loggable注解的方法。 Aspect
Component
public class LoggingAspect {Around(annotation(loggable))public Object logExecutionTime(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {long start System.currentTimeMillis();Object proceed joinPoint.proceed(); // 执行目标方法long executionTime System.currentTimeMillis() - start;// 记录日志的逻辑logger.info(joinPoint.getSignature() executed in executionTime ms);return proceed;}
} 1.3 配置Spring AOP标记注解 Configuration
EnableAspectJAutoProxy
public class AopConfig {// 可能还需要其他的配置或Bean定义
}public class SomeService {Loggablepublic void someBusinessMethod(Object someParam) {// 业务逻辑}
} 1.4 定义日志记录逻辑 在切面中我们就可以自定义日志记录逻辑可以记录更多的上下文信息如方法参数、返回值、执行时间、异常信息等。 Autowired
private Logger logger; // 例如通过SLF4J获取的LoggerAround(annotation(loggable))
public Object logBusinessOperation(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {// 方法执行前的逻辑例如记录开始时间、方法参数等long start System.currentTimeMillis();try {Object result joinPoint.proceed(); // 执行目标方法// 方法执行后的逻辑例如记录结束时间、返回值等return result;} catch (Exception e) {// 异常处理逻辑如记录异常信息throw e;} finally {long executionTime System.currentTimeMillis() - start;// 构建日志信息并记录logger.info({} executed in {} ms, joinPoint.getSignature(), executionTime);}
} •业务操作场景划分切面的定义和使用都是非业务化的所以无法感知到新的业务操作范围和业务的定义划分边界是如何处理 •级联操作断档当业务操作是设计多表或者多个服务间的调用串联时切面只能单独记录每个服务方法级别的数据信息无法对调用链的部分进行业务串联 Repeatable(LogRecords.class)
Target({ElementType.METHOD, ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Inherited
Documented
public interface LogRecord {String success();String fail() default ;String operator() default ; //业务操作场景人String type(); // 业务场景 模块范围String subType() default ; //业务子场景主要是模块下的功能范围String bizNo(); //业务场景的业务编号String extra() default ;//一些操作的扩展操作String actionType(); //业务操作类型比如编辑、新增、删除
} Binlog大家都不陌生是数据库中二进制格式的文件用于记录用户对数据库更新的SQL语句信息例如更改数据库表和更改内容的SQL语句都会记录到binlog里。那么Binlog能用来记录业务层面的数据变化内容吗 3.1 Binlog Binlog大家都不陌生是数据库中二进制格式的文件用于记录用户对数据库更新的SQL语句信息例如更改数据库表和更改内容的SQL语句都会记录到binlog里。那么Binlog能用来记录业务层面的数据变化内容吗 •问题1:无法对多表存在级联保存和更新的数据进行非常好的兼容支持因为本身binlog数据是无序的并且如果上游数据的操作不是包裹在一个事务中也很难处理 •问题2:关于更新人的问题系统进行更新时如果未手动更新对应操作人则系统无法识别需要上游做对应场景的统一改造但从系统承接来看本身系统的操作人就是要跟着业务操作一起进行联动的 MVCC MVCC最大的好处是读不加锁读写不冲突在读多写少的系统应用中读写不冲突是非常重要的可极大提升系统的并发性能这也是为什么现阶段几乎所有的关系型数据库都支持 MVCC 的原因目前MVCC只在 Read Commited 和 Repeatable Read 两种隔离级别下工作。它是通过在每行记录的后面保存两个隐藏列来实现的这两个列 一个保存了行的创建时间一个保存了行的过期时间 存储的并不是实际的时间值而是系统版本号。MVCC在mysql中的实现依赖的是undo log与read view。 read view 在 MVCC 并发控制中读操作可以分为两类: 快照读Snapshot Read与当前读 Current Read。 •快照读读取的是记录的快照版本有可能是历史版本不用加锁select。 •当前读读取的是记录的最新版本并且当前读返回的记录都会加锁保证其他事务不会再并发修改这条记录(select… for update 、lock或insert/delete/update。 redo log redo log叫做重做日志。mysql 为了提升性能不会把每次的修改都实时同步到磁盘而是会先存到Buffer Pool(缓冲池)里当作缓存来用以提升性能使用后台线程去做缓冲池和磁盘之间的同步。那么问题来了如果还没来及的同步的时候宕机或断电了怎么办这样会导致丢部分已提交事务的修改信息所以引入了redo log来记录已成功提交事务的修改信息并且会把redo log持久化到磁盘系统重启之后再读取redo log恢复最新数据。redo log是用来恢复数据的保障已提交事务的持久化特性。 undo log undo log 叫做回滚日志用于记录数据被修改前的信息。他正好跟前面所说的重做日志所记录的相反重做日志记录数据被修改后的信息。undo log主要记录的是数据的逻辑变化。为了在发生错误时回滚之前的操作需要将之前的操作都记录下来然后在发生错误时才可以回滚。undo log 记录事务修改之前版本的数据信息假如由于系统错误或者rollback操作而回滚的话可以根据undo log的信息来进行回滚到没被修改前的状态。undo log是用来回滚数据的保障未提交事务的原子性。 假设 F1F6 是表中字段的名字16 是其对应的数据。后面三个隐含字段分别对应该行的隐含ID、事务号和回滚指针 具体的更新过程如下 假如一条数据是刚 INSERT 的DB_ROW_ID 为 1其他两个字段为空。当事务 1 更改该行的数据值时会进行如下操作 •用排他锁锁定该行记录 Redo log •把该行修改前的值复制到 Undo log •修改当前行的值填写事务编号并回滚指针指向 Undo log 中修改前的行。 如果再有事务2操作过程与事务 1 相同此时 Undo log 中会有两行记录并且通过回滚指针连在一起通过当前记录的回滚指针回溯到该行创建时的初始内容 这里的undolog不会一直增加purge thread在后面会进行undo page的回收也就是清理undo log。 JDBC-jre system library - rt.jar(sql,Connection.class, Driver.class,) // 创建数据库连接
Connection connection DriverManager.getConnection(jdbc:mysql://localhost:3306/easyflow, root, 12345678);
// 自动提交设置
connection.setAutoCommit(false);
// 只读设置
connection.setReadOnly(false);
// 事务隔离级别设置
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
// 创建查询语句
PreparedStatement statement connection.prepareStatement(update config set cfg_value1 where id11111);
// 执行SQL
int num statement.executeUpdate();
System.out.println(更新行数: num);
// 事务提交
connection.commit(); Mybatis事务相关 Mybatis核心是提供了sql查询方法、结果集与应用方法及对象之间的映射关系便于开发人员进行数据库操作。 事务transactionJDBC对接数据源datasource反射reflectionIO封装游标cursor异常exceptions字节码处理javassist会话session执行器executor映射mapping映射binding构建器builder模版引擎ognl解析器parsing脚本处理scripting缓存cache日志logging插件plugin类型type注解annotationjava版本lang 加群联系作者vxxiaoda0423 仓库地址https://github.com/webVueBlog/JavaGuideInterview