工作笔记(四)

开发问题:

1.不能用本地构建,替换生产环境包,比如一些配置文件不同,dubbo.properties,application.properties,disconf.properties.

2.Hbase设计分区策略

rowKey加上前缀 hash(rowkey),当使用String.hashCode()时,出现负值。

String类的hashCode方法是通过int来修饰的,只要hashcode的计算结果超出了int的范围就会产生溢出

解决方法:加绝对值。

Java 相关问题

1.如何设计key让hashMap没有冲突?

2.static方法都有哪些用法?

变量、方法、代码块、内部类

3.内部类可以用static吗?

Java里面static一般用来修饰成员变量函数

但有一种特殊用法是用static修饰内部类。普通类是不允许声明为静态的,只有内部类才可以。

被static修饰的内部类可以直接作为一个普通类来使用,而不需先实例一个外部类。

参考链接:https://blog.youkuaiyun.com/hbtj_1216/article/details/77101234

4.static修饰的方法和变量、代码块都是什么时候加载的?

在类中用static{},修饰的块被称为静态块。主要用于给静态变量赋值,调用静态方法。在类加载的时候执行一次。静态块中的代码只在类加载的过程中执行一次。在虚拟机jvm的生命周期中所有的类只会加载一次,而静态块又是伴随类加载而加载。不管你new出多少新的实例,静态块只会加载一次。

java中static方法在显式调用的时候执行,static方法不同于static块,不会自动执行的,只有你在代码中显示的调用,即类名.静态方法名();才会执行。

5.Collections.synchronizedMap()与ConcurrentHashMap主要区别

ConcurrentHashMap的实现过程,其中有提到在put操作时,如果发现链表结构中的元素超过了TREEIFY_THRESHOLD(默认为8),则会把链表转换为红黑树,已便于提高查询效率。

collections.synchronizedmap 可以将hashmap变成线程安全的类

Collections.synchronizedMap()与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步,而ConcurrentHashMap的实现却更加精细,它对map中的所有桶加了锁。所以,只要要有一个线程访问map,其他线程就无法进入map,而如果一个线程在访问ConcurrentHashMap某个桶时,其他线程,仍然可以对map执行某些操作。这样,ConcurrentHashMap在性能以及安全性方面,明显比Collections.synchronizedMap()更加有优势。同时,同步操作精确控制到桶,所以,即使在遍历map时,其他线程试图对map进行数据修改,也不会抛出ConcurrentModificationException。

6.char和varchar的区别
5.String中有哪些方法?

1.equals 2.length 3.chartAt() 4.replace() 5.startWith() 6.endsWith() 7.subString()

8.contains() 9.split() 10.compareTo() 11.toCharArray() 12.replaceAll() 13.indexOf()

14.lastIndexOf() 15.concat() 16.equalsIgnoreCase() 17.toLowerCase() 18.toUpperCase()

7.CharSequence和String区别?

CharSequence是一个接口,本身是没有什么读写意义的。String只是它的一个实现类,虽然String是只读,但是CharSequence的实现类还有StringBuffer,StringBuilder这些可写的,所以用CharSequence作为参数可以接收String,StringBuffer,StringBuilder这些类型。

Aviator 规则引擎

参考链接:https://github.com/killme2008/aviator/wiki

Drools

java开源的规则引擎有:Drools、Easy Rules、Mandarax、IBM ILOG。使用最为广泛并且开源的是Drools。将规则和代码解耦。

负载均衡算法

参考链接:https://www.cnblogs.com/szlbm/p/5588555.html

负载均衡,英文 名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种 负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡能够平均分配客户请求到服 务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集群技术可以用最少的投资获得接近于大型主机的性能。

负载均衡分为软件负载均衡和硬件负载均衡,前者的代表是阿里章文嵩博士研发的LVS,后者则是均衡服务器比如F5,当然这只是提一下,不是重点。

本文讲述的是"将外部发送来的请求均匀分配到对称结构中的某一台服务器上"的各种算法

加权随机(Weight Random)法

与加权轮询法类似,加权随机法也是根据后端服务器不同的配置和负载情况来配置不同的权重。不同的是,它是按照权重来随机选择服务器的,而不是顺序。加权随机法的代码实现如下:

public class WeightRandom
{
    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap = 
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);
        
        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        Iterator<String> iterator = keySet.iterator();
        
        List<String> serverList = new ArrayList<String>();
        while (iterator.hasNext())
        {
            String server = iterator.next();
            int weight = serverMap.get(server);
            for (int i = 0; i < weight; i++)
                serverList.add(server);
        }
        
        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(serverList.size());
        
        return serverList.get(randomPos);
    }
}

Redis

为什么Redis是单线程的?

redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案

那什么时候用多线程的方案呢?

答案是:下层的存储等慢速的情况。比如磁盘

redis作为单进程模型的程序,为了充分利用多核CPU,常常在一台server上会启动多个实例。而为了减少切换的开销,有必要为每个实例指定其所运行的CPU。

作者:world6
来源:优快云
原文:https://blog.youkuaiyun.com/world6/article/details/79381682
版权声明:本文为博主原创文章,转载请附上博文链接!

为什么Redis 单线程却能支撑高并发?

Redis可以支撑10万并发

在 I/O 多路复用模型中,最重要的函数调用就是 select,该方法的能够同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时, select 方法就会返回可读以及可写的文件描述符个数。

由于 epoll 相比 select 机制略有不同,在 epoll_wait 函数返回时并不需要遍历所有的 FD 查看读写情况;在 epoll_wait 函数返回时会提供一个 epoll_event 数组:

其中保存了发生的 epoll 事件( EPOLLINEPOLLOUTEPOLLERREPOLLHUP)以及发生该事件的 FD。

aeApiPoll 函数只需要将 epoll_event 数组中存储的信息加入 eventLoopfired 数组中,将信息传递给上层模块:

epoll时间复杂度是O(1), 监听活跃的文件描述符;select时间复杂度是O(N);由于其在使用时会扫描全部监听的描述符,所以其时间复杂度较差 O(n)

子模块的选择

因为 Redis 需要在多个平台上运行,同时为了最大化执行的效率与性能,所以会根据编译平台的不同选择不同的 I/O 多路复用函数作为子模块,提供给上层统一的接口;在 Redis 中,我们通过宏定义的使用,合理的选择不同的子模块:

因为 select 函数是作为 POSIX 标准中的系统调用,在不同版本的操作系统上都会实现,所以将其作为保底方案:

参考链接:https://maimai.cn/article/detail?fid=1234808844&efid=8bQN4wg_nj2hlfppxgJKxQ&from=single_feed

简书:https://www.jianshu.com/p/2d293482f272

Mybatis一级缓存和二级缓存

https://www.cnblogs.com/ysocean/p/7342498.html

①、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

和一级缓存默认开启不一样,二级缓存需要我们手动开启

文件操作符

NIO BIO深入理解

数据库三大范式

参考链接:https://segmentfault.com/a/1190000013695030

一、第一范式

1NF是对属性的原子性,要求属性具有原子性,不可再分解;

表:字段1、 字段2(字段2.1、字段2.2)、字段3 …

如学生(学号,姓名,性别,出生年月日),如果认为最后一列还可以再分成(出生年,出生月,出生日),它就不是一范式了,否则就是;

二、第二范式

2NF是对记录的惟一性,要求记录有惟一标识,即实体的惟一性,即不存在部分依赖;

表:学号、课程号、姓名、学分;

这个表明显说明了两个事务:学生信息, 课程信息;由于非主键字段必须依赖主键,这里学分依赖课程号姓名依赖与学号,所以不符合二范式。

可能会存在问题:

  • 数据冗余:,每条记录都含有相同信息;
  • 删除异常:删除所有学生成绩,就把课程信息全删除了;
  • 插入异常:学生未选课,无法记录进数据库;
  • 更新异常:调整课程学分,所有行都调整。

正确做法:
学生:Student(学号, 姓名);
课程:Course(课程号, 学分);
选课关系:StudentCourse(学号, 课程号, 成绩)。

三、第三范式

3NF是对字段的冗余性,要求任何字段不能由其他字段派生出来,它要求字段没有冗余,即不存在传递依赖;

表: 学号, 姓名, 年龄, 学院名称, 学院电话

因为存在依赖传递: (学号) → (学生)→(所在学院) → (学院电话) 。

可能会存在问题:

  • 数据冗余:有重复值;
  • 更新异常:有重复的冗余信息,修改时需要同时修改多条记录,否则会出现数据不一致的情况

正确做法:

学生:(学号, 姓名, 年龄, 所在学院);

学院:(学院, 电话)。

四、反范式化

一般说来,数据库只需满足第三范式(3NF)就行了。

没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余,达到以空间换时间的目的

〖例〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加“金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。

Rose 2002中,规定列有两种类型:数据列计算列。“金额”这样的列被称为“计算列”,而“单价”和“数量”这样的列被称为“数据列”。

参考资料如下:

1、通俗地理解数据库三个范式
2、数据库模型设计,第一范式、第二范式、第三范式简单例子理解
3、数据库三大范式最简单的解释

MYSQL日期
###MySQL 日期类型:日期格式、所占存储空间、日期范围 比较。
 日期类型        存储空间       日期格式                 日期范围 

------

datetime       8 bytes   YYYY-MM-DD HH:MM:SS   1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 
timestamp      4 bytes   YYYY-MM-DD HH:MM:SS   1970-01-01 00:00:01 ~ 2038 
date           3 bytes   YYYY-MM-DD            1000-01-01          ~ 9999-12-31 
year           1 bytes   YYYY                  1901                ~ 2155

`create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 
【更新时间字段保存后生效;null default null含义:可以为null 默认为null】

mybatis-generator

mybatis-generator的指令需要在命令行中运行,
这个需要在命令行中将光标定位到mybatis-generator-core-1.3.6.jar所在的目录,然后执行下面的指令:

java -jar mybatis-generator-core-1.3.6.jar -configfile generatorConfig.xml -overwrite

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
	<!-- <classPathEntry location="D:\repository\mysql\mysql-connector-java\5.1.35\mysql-connector-java-5.1.35-sources.jar" 
		/> -->
	<!--数据库驱动-->
    <classPathEntry    location="D:\java\IntellijIdea\gradle_repo\caches\modules-2\metadata-2.56\descriptors\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar"/>
    
	<context id="context1">
		<commentGenerator>
			<property name="suppressAllComments" value="true" />
		</commentGenerator>
		<!-- <jdbcConnection driverClass="com.mysql.jdbc.Driver"
			connectionURL="jdbc:mysql://10.166.224.18:6000/zsy_ddb_dev" userId="zsy_dev"
			password="J0e2Z2odHGqV" /> -->
		
		<jdbcConnection driverClass="com.mysql.jdbc.Driver"	connectionURL="jdbc:mysql://10.107.xx.xxx:3306/abcd" userId=""	password="" />
		<!-- <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@10.166.225.57:1521:zsydev" 
			userId="ap_accountant" password="ap_accountant_dev234312" /> -->
		<javaModelGenerator targetPackage="cn.webank.entity"
			targetProject="src" />
		<sqlMapGenerator targetPackage="cn.webank.daoMapper" targetProject="src" />
		<javaClientGenerator targetPackage="cn.webank.dao"
			targetProject="src" type="XMLMAPPER" />
			
		<table tableName="acquire_amt_limit"
			enableSelectByExample="false" enableCountByExample="false"
			enableUpdateByExample="false" enableDeleteByExample="false"
			selectByExampleQueryId="false">
		</table>

	</context>
</generatorConfiguration>

事务隔离级别

为了避免上面出现的几种情况,在标准SQL规范中,定义了4个事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。

未提交读取(Read Uncommitted)

Spring标识:ISOLATION_READ_UNCOMMITTED。允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。

已提交读取(Read Committed)

Spring标识:ISOLATION_READ_COMMITTED。允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

可重复读取(Repeatable Read)

Spring标识:ISOLATION_REPEATABLE_READ。禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

序列化(Serializable)

Spring标识:ISOLATION_SERIALIZABLE。提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。**对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。**它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

Spring中同时提供一个标识:ISOLATION_DEFAULT。表示使用后端数据库默认的隔离级别。大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。MySQL的默认隔离级别是Repeatable read。
Connection.TRANSACTION_READ_UNCOMMITTED :level=1,
Connection.TRANSACTION_READ_COMMITTED: level=2,
Connection.TRANSACTION_REPEATABLE_READ : level=4,
Connection.TRANSACTION_SERIALIZABLE : level=8,
一般使用的时候,根据Connetion连接对象设置参数:
数据库连接对象.setTransactionIsolation(参数);
参数:1,2,4,8

git merge和git rebase

参考:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA
提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次。 在 Git 中,这种操作就叫做 变基。 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。 你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的,但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。

一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。 在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码变基到 origin/master 上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。

请注意,无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值