首页
留言板
友链
关于
Search
1
内测“合金弹头”嘿嘿
889 阅读
2
Nginx搭建一个简易的图床
839 阅读
3
Kettle循环遍历结果集作为参数传入转换
820 阅读
4
Apache Dubbo初步认识
437 阅读
5
Maven3.3.9的安装与配置
419 阅读
知识库
好奇猫
日常说
笔记本
登录
/
注册
Search
标签搜索
maven
Spring
vue
Java
Java代码
前端
idea
帆软
MySQL
git
CSS
游戏
Bootstrap
生活
网上冲浪
邮件配置
说说
Nginx
Excel
数据库调优
龙流
累计撰写
61
篇文章
累计收到
18
条评论
首页
栏目
知识库
好奇猫
日常说
笔记本
页面
留言板
友链
关于
搜索到
39
篇与
笔记本
的结果
2022-06-14
Kettle循环遍历结果集作为参数传入转换
kettle入门就不详细说明了,记录一下结合业务需求开发一个kettle工作流定时抽取数据。简单描述就是:‘Kettle循环遍历结果集作为参数传入转换’图文说明暂时参考链接
2022年06月14日
820 阅读
0 评论
0 点赞
2022-06-09
'搬砖’搜索比较多的操作
SQL Server 设置主键自增长:新增时:CREATE TABLE [dbo].[rescue_material_configure] ( [id] int IDENTITY(1,1) NOT NULL, [category_id] int NOT NULL, [material_name] varchar(100) COLLATE Chinese_PRC_CI_AS NULL, [base] varchar(100) COLLATE Chinese_PRC_CI_AS NULL, [operate_date] datetime NOT NULL )修改表时:ALTER TABLE [dbo].[nurse_impower_type_content] DROP COLUMN id; ALTER TABLE [dbo].[nurse_impower_type_content] ADD id BIGINT Identity(1,1) NOT NULL;SQL Server增加字段注释表注释EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'表注释' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=表名'增加字段注释execute sp_addextendedproperty 'MS_Description','字段注释','user','dbo','table','表名','column','字段名';SQL Server 各种时间日期查询链接查询昨天日期:select convert(char,dateadd(DD,-1,getdate()),111) //111是样式号,(100-114) 查询半年前的现在日期时间:select DATEADD(MM,-6,GETDATE()) 查询一个月前当前的日期时间:select DATEADD(MM,-1,GETDATE())
2022年06月09日
76 阅读
0 评论
0 点赞
2022-06-08
java清理缓存实现
前台代码:<script> function CleanConfirm(){ var url="/devindex/function"; var data={f:'clearCache'}; $.ajax({ url: url, type: "post", dataType: "json", contentType: "application/json; charset=utf8", data: data, success: function(data) { if(data.success){ layerInfo(data.msg); }else{ layerInfo(data.msg); } } }); } </script>后台代码:@ResponseBody @RequestMapping({"/function"}) public Map function(String p_dm, @RequestParam Map<String, Object> paramMap, Model model, HttpServletRequest request, HttpServletResponse response) { if ("clearCache".equals(paramMap.get("f"))) { CommonCacheManager commonCacheManager = CommonCacheManager.getCommonCacheManager(); String cacheName = CACHENAME.COMMONAPICONFIG.name(); List<PFunctionsubEntity> pFunctionsubEntities = this.pFunctionSubService.GetOneDataByDm(p_dm); for(int i = 0; i < pFunctionsubEntities.size(); ++i) { PFunctionsubEntity pFunctionsubEntity = (PFunctionsubEntity)pFunctionsubEntities.get(i); commonCacheManager.removeCacheValue(cacheName, pFunctionsubEntity.getId()); commonCacheManager.removeCacheValue(cacheName, pFunctionsubEntity.getDm()); commonCacheManager.removeCacheValue(cacheName, pFunctionsubEntity.getMainid() + pFunctionsubEntity.getDm()); commonCacheManager.removeCacheValue(cacheName, pFunctionsubEntity.getId() + PFunctiontjoptEntity.class.toString()); commonCacheManager.clearCache(pFunctionsubEntity.getDm()); } if (StringUtil.isEmptyOrLength0(p_dm)) { commonCacheManager.clearCache(cacheName); commonCacheManager.clearCache((String)null); } Map resMap = new HashMap(); resMap.put("success", "true"); resMap.put("msg", "clearCache:" + (StringUtil.isEmptyOrLength0(p_dm) ? "all" : p_dm)); return resMap; } }
2022年06月08日
103 阅读
0 评论
0 点赞
2022-04-19
本地项目上传到”码云“
登录"码云" 登录或注册码云,进入主页后点击+号新建仓库,如下图为避免error: failed to push some refsto‘远程仓库地址’的错误不要勾选“使用Readme文件初始化这个仓库”根据向导,可直接点击立即创建即可.使用git应用 未安装git的可参考此文章.命令行模式下,进行要上传到git的目录下:初始化本地仓库git命令:git init上传他人拷贝给自己的项目时,拷贝过来的文件夹中如果有.git目录(注意此文件夹是隐藏文件夹)使用命令关联远端仓库git remote add origin 远端仓库地址查看当前配置信息git config --list 使用git status命令查看仓库文件状态-s 选项——精简输出具体参考第一列字符表示版本库与暂存区之间的比较状态。第二列字符表示暂存区与工作区之间的比较状态。' ' (空格)表示文件未发生更改M 表示文件发生改动。A 表示新增文件。D 表示删除文件。R 表示重命名。C 表示复制。U 表示更新但未合并。? 表示未跟踪文件。! 表示忽略文件。未跟踪和忽略文件会显示相同的两列,如 ??。先将修改过的文件添加到暂存区域,执行添加指令git add .再将暂存区域的文件,提交至本地仓库,执行提交指令git commit -m"commit msg"最后将本地仓库推送至远端仓库,执行推送指令git push origin master注意:如果用户信息输入有误,会提示 remote: Invalid username or password.再次执行推送指令,即可重新填写用户信息。了解:当本地仓库与远程仓库不一致时,推送并合并分支git pull --rebase origin mastergit pull origin master【Git】git pull origin master与git pull --rebase origin master的区别:git pull=git fetch + git mergegit pull --rebase=git fetch+git rebasegit fetch : 从远程分支拉取代码,可以得到远程分支上最新的代码。所以git pull origin master与git pull --rebase origin master的区别主要是在远程与本地代码的合并上面了。对比可看出:git merge多出了一个新的节点G,会将远端master的代码和test本地的代码在这个G节点合并,之前的提交会分开去显示。git --rebase会将两个分支融合成一个线性的提交,不会形成新的节点。rebase好处想要更好的提交树,使用rebase操作会更好一点。这样可以线性的看到每一次提交,并且没有增加提交节点。merge 操作遇到冲突的时候,当前merge不能继续进行下去。手动修改冲突内容后,add 修改,commit 就可以了。而rebase 操作的话,会中断rebase,同时会提示去解决冲突。解决冲突后,将修改add后执行git rebase –continue继续操作,或者git rebase –skip忽略冲突。
2022年04月19日
50 阅读
0 评论
0 点赞
2022-04-18
IBM MQ使用,传递消息
参考连接Jquery发送ajax请求get $.get("[后台请求地址]",{},[回调方法]function(data[返回的数据data]){ //业务处理。。。 }); $.get("category/findAll",{},function(data){} var lis = '首页'; for(var i = 0; i < data.length; i++) { //动态拼接 var li = '+ data[i].cname +'; lis += li; } //拼接尾部 lis += '收藏' //将lis字符串输出到标签中 $(#category).html(lis); );
2022年04月18日
64 阅读
0 评论
0 点赞
2022-03-27
Redis
redis的5种数据类型:string 字符串(可以为整形、浮点型和字符串,统称为元素)hash hash散列值(hash的key必须是唯一的)list 列表(实现队列,元素不唯一,先入先出原则)set 集合(各不相同的元素)sort set 有序集合string类型的常用命令:添加:set获取:get自加:incr自减:decr加: incrby减: decrbylist类型支持的常用命令:lpush:从左边推入lpop:从右边弹出rpush:从右变推入rpop:从右边弹出llen:查看某个list数据类型的长度set类型支持的常用命令:sadd:添加数据scard:查看set数据中存在的元素个数sismember:判断set数据中是否存在某个元素srem:删除某个set数据中的元素hash数据类型支持的常用命令:hset:添加hash数据hget:获取hash数据hmget:获取多个hash数据sort set和hash很相似,也是映射形式的存储:zadd:添加zcard:查询zrange:数据排序Redis的持久化redis持久化机制: 1、RDB:默认方式,不需要进行配置,默认就使用这种机制 在一定的间隔时间中,检测key的变化情况,然后持久化数据 redis安装目录下的配置文件:redis.windows.conf #900秒(15min)之后如果有一个Key发生改变就进行一次持久化 save 900 1 #300秒(5min)之后如果有10个Key发生改变就进行一次持久化 save 300 10 #60秒(1min)之后如果有10000个Key发生改变就进行一次持久化 save 60 10000 2、AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据使用配置的启动方式:命令行 redis-server.exe redis.windows.confredis缓存操作eg:缓存一些数据库中不宜发生改变的数据,如省份信息;将数据库中的省份信息以JSON字符串的形式保持在缓存中,每次查询时先查缓存,没有再去查询数据库 注意点:要保证redis数据与数据库的一直性,对数据库中的省份信息进行增删改操作时,要更新缓存。
2022年03月27日
60 阅读
0 评论
0 点赞
2022-03-25
javax.servlet.Filter与动态代理
Java过滤器 Fileter快速入门:1、定义一个类,实现**javax.servlet.Filter**接口 2、重写其3个方法,init(); doFilter(); destroy(); 3、配置拦截资源: 通过web.xml配置 注解配置 @WebFilter("urlPatterns") web.xml<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <filter-name>demo1</filter-name> <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>demo1</filter-name> <!-- 拦截路径 --> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>Filter实现代码public class FilterDemo implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo1被执行了...."); //放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() {} }过来器生命周期1、init()方法,会在Filter对象创建时执行一次。一般可以用来加载资源2、doFilter()方法,会执行多次,符合拦截规则的请求,在请求到资源前都会执行该方法,filterChain.doFilter(servletRequest,servletResponse)放行,拿到资源后,即进行响应时会走放行后的代码3、destroy()方法,会在Filter对象被正常消耗时会执行一次。过滤器链(配置多个过滤器) * 执行顺序:如果有两个过滤器:过滤器1和过滤器2 1. 过滤器1 2. 过滤器2 3. 资源执行 4. 过滤器2 5. 过滤器1 * 过滤器先后顺序问题: 1. 注解配置:按照类名的字符串比较规则比较,值小的先执行 * 如: AFilter 和 BFilter,AFilter就先执行了。 2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行 使用动态代理增强Filter过滤器中的doFilter(servletRequest,servletResponse)方法的servletRequest对象的getParameter()方法动态代理 * 概念: 1. 真实对象:被代理的对象 2. 代理对象: 3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 * 实现方式: 1. 静态代理:有一个类文件描述代理模式 2. 动态代理:在内存中形成代理类 * 实现步骤: 1. 代理对象和真实对象实现相同的接口 2. 代理对象 = Proxy.newProxyInstance(); 3. 使用代理对象调用方法。 4. 增强方法 * 增强方式: 1. 增强参数列表 2. 增强返回值类型 3. 增强方法体执行逻辑 @Override public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException { //1、创建代理对象,增强getParameter()方法 ServletRequest request_proxy = (ServletRequest)Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvokeHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //要增强getParameter(),所以进行个判断 if("getParameter".equals(method.getName())){ //增强返回值,对request对象值请求参数中的值进行个修改 String parameter = (String)method.invoke(servletRequest,args); //进行修改然后返回 return parameter.replace("#",""); }else { return method.invoke(servletRequest,args); } } }); //2、放行 filterChain.doFilter(); }
2022年03月25日
66 阅读
0 评论
0 点赞
2022-03-24
java.lang.String的substring、split方法引起的内存问题
项目运行遇到了OutOfMemoryError异常.内存溢出?觉得是不是MaxPermSize设置小了,又给了1个G的大小,试下还是不行,然后使用Java heap分析工具,找出内存占用超出预期的嫌疑对象dump heapHeap Dump也叫堆转储文件,是一个Java进程在某个时间点上的内存快照。Heap Dump是有着多种类型的。不过总体上heap dump在触发快照的时候都保存了java对象和类的信息。通常在写heap dump文件前会触发一次FullGC,所以heap dump文件中保存的是FullGC后留下的对象信息。关于Heap Dump使用jconsole获取dump heap:建立连接后,选择页签MBean,执行com.sun.management. HotSpotDiagnostic下的操作dumpHeap。第一个参数p0是要获取的dump文件的完整路径名,记得文件要以.hprof作为扩展名(要在Memory AnalysisPerspective下打开扩展名必须是这个)。如果我们只想获取live的对象,第二个参数p1需要保持为true。JDK自带的jmap工具:Java代码jmap -dump:format=b,file=heap.bin <pid> format=b的含义是,dump出来的文件时二进制格式。 file-heap.bin的含义是,dump出来的文件名是heap.bin。 <pid>就是JVM的进程号。 (在linux下)先执行ps aux | grep java,找到JVM的pid;然后再执行jmap -dump:format=b,file=heap.bin <pid>,得到heap dump文件。analyze heap将二进制的heap dump文件解析成human-readable的信息,自然是需要专业工具的帮助,Memory Analyzer Memory Analyzer,简称MAT,是Eclipse基金会的开源项目,由SAP和IBM捐助。巨头公司出品的软件还是很中用的,MAT可以分析包含数亿级对 象的heap、快速计算每个对象占用的内存大小、对象之间的引用关系、自动检测内存泄露的嫌疑对象,功能强大,而且界面友好易用。 MAT的界面基于Eclipse开发,以两种形式发布:Eclipse插件和Eclipe RCP。MAT的分析结果以图片和报表的形式提供,一目了然。{gird column="2" gap="15"}{gird-item}{/gird-item}{gird-item}{/gird-item}{/gird}最后发现到这里内存突然就爆增看到这里我就觉得是不是split()使用的有什么问题于是就上网查了一下split学习了一下。原文连接:https://blog.csdn.net/caihaijiang/article/details/7748560先用一个极端例子说明String的substring方法引起的OutOfMemoryError问题:public class TestGC { private String large = new String(new char[100000]); public String getSubString() { return this.large.substring(0,2); } public static void main(String[] args) { ArrayList<String> subStrings = new ArrayList<String>(); for (int i = 0; i <1000000; i++) { TestGC testGC = new TestGC(); subStrings.add(testGC.getSubString()); } } }:对一个很长的字符串,使用substring循环保留该字符串里面的一小部分,保存到HashMap中运行该程序,结果出现:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space为什么会出现这个情况?查看一下JDK String类substring方法的源码,可以找到原因,源码如下: public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex > endIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value); }该方法最后一行,调用了String的一个私有的构造方法,如下: // Package private constructor which shares value array for speed. String(int offset, int count, char value[]) { this.value = value; this.offset = offset; this.count = count; }该方法为了避免内存拷贝,提高性能,并没有重新创建char数组,而是直接复用了原String对象的char[],通过改变偏移量和长度来标识不同的字符串内容。也就是说,substring出的来String小对象,仍然会指向原String大对象的char[],所以就导致了OutOfMemoryError问题。找到问题之后,将上面代码中,getSubString的方法修改一下,如下: public String getSubString() { return new String(this.large.substring(0,2)); }将substring的结果,重新new一个String出来。再运行该程序,则没有出现OutOfMemoryError的问题。为什么?因为此时调用的是String类的public的构造方法,该方法源码如下: public String(String original) { int size = original.count; char[] originalValue = original.value; char[] v; if (originalValue.length > size) { // The array representing the String is bigger than the new // String itself. Perhaps this constructor is being called // in order to trim the baggage, so make a copy of the array. int off = original.offset; v = Arrays.copyOfRange(originalValue, off, off+size); } else { // The array representing the String is the same // size as the String, so no point in making a copy. v = originalValue; } this.offset = 0; this.count = size; this.value = v; }从代码可以看出,在String对象中value的length大于count的情况下,会重新创建一个char[],并进行内存拷贝。除了substring方法之后,String的split方法,也存在同样的问题,split的源码如下: public String[] split(String regex, int limit) { return Pattern.compile(regex).split(this, limit); }可以看出,String的split方法通过Pattern的split方法来实现,Pattern的split方法源码如下:public String[] split(CharSequence input, int limit) { int index = 0; boolean matchLimited = limit > 0; ArrayList<String> matchList = new ArrayList<String>(); Matcher m = matcher(input); // Add segments before each match found while(m.find()) { if (!matchLimited || matchList.size() < limit - 1) { String match = input.subSequence(index, m.start()).toString(); matchList.add(match); index = m.end(); } else if (matchList.size() == limit - 1) { // last one String match = input.subSequence(index, input.length()).toString(); matchList.add(match); index = m.end(); } } // If no match was found, return this if (index == 0) return new String[] {input.toString()}; // Add remaining segment if (!matchLimited || matchList.size() < limit) matchList.add(input.subSequence(index, input.length()).toString()); // Construct result int resultSize = matchList.size(); if (limit == 0) while (resultSize > 0 && matchList.get(resultSize-1).equals("")) resultSize--; String[] result = new String[resultSize]; return matchList.subList(0, resultSize).toArray(result); }方法中的第9行: Stirng match = input.subSequence(intdex, m.start()).toString();调用了String类的subSequence方法,该方法源码如下: public CharSequence subSequence(int beginIndex, int endIndex) { return this.substring(beginIndex, endIndex); }通过代码可以看出,最终调用的是String类的substring方法,因此存在同样的问题。split出来的小对象,直接使用原String对象的char[]。看了一下StringBuilder和StringBuffer的substring方法,则不存在这样的问题。其源码如下: public String substring(int start, int end) { if (start < 0) throw new StringIndexOutOfBoundsException(start); if (end > count) throw new StringIndexOutOfBoundsException(end); if (start > end) throw new StringIndexOutOfBoundsException(end - start); return new String(value, start, end - start); }最后一行,调用了String类的public构造方法,方法源码如下: public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.offset = 0; this.count = count; this.value = Arrays.copyOfRange(value, offset, offset+count); }方法不是直接使用原String对象的char[],而是重新进行了内存拷贝。
2022年03月24日
199 阅读
0 评论
0 点赞
2022-03-23
序列化与反序列化
把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。对象的序列化主要有两种用途:把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;在网络上传送对象的字节序列。使用场景 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些session先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。 当两个进程在进行远程通信时,当我们需要使用的对象很复杂或者需要很长时间去构造,这时就会引入使用代理模式(Proxy)。例如:如果构建一个对象很耗费时间和计算机资源,代理模式(Proxy)允许我们控制这种情况,直到我们需要使用实际的对象。一个代理(Proxy)通常包含有和将要使用的对象同样的方法,一旦开始使用这个对象,这些方法将通过代理(Proxy)传递给实际的对象。解读:在微服务化盛行的今天,很多复杂的对象构造起来比较耗时,为了节省开支,某些公司将这部分复杂的对象先圈起来,写成服务起在远端B,并在调用端A端以代理(Proxy)的形式提供对服务的访问,这期间从B到A远程调的过程形成了Java对象序列化和反序列化的相关操作!深入理解JDK提供了个代理类:import java.lang.reflect.Proxy; 来看一下Proxy的实现Proxy在JDK中实现了Serializable(序列化)接口,但是代理是怎么实现将服务端的对象运行到客户端上的呢?第一步:远端JVM(服务端)对“对象”使用序列化后通过网络传输的方式将对象的字节序列发送到本地(客户端)第二步:本地代理(Proxy)将接收到的字节序列再通过反序列化恢复成”对象”,并使这个"对象"活在本地的JVM中;从上面两步来看,序列化的过程是在服务端做的;反序列化是在客户端做的;那么有个问题来了,从源码上看,Proxy(本地)实现了反序列化,服务端在哪里实现了序列化呢?带着这个问题,继续查看了服务端所有的代码,发现有的公司直接在实体上Serialize,有的则在类上加@Serializable注解利用切面实现,但终究实现了序列化;JDK类库中的序列化APIjava.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。 只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。对象序列化/** * @ClassName: Student * @author: WeiLong * @description 学生类 */ public class Student implements Serializable{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }注意:需要序列化的类需要实现Serializable接口,获取上述其他方法,否则会出现NotSerializableException //实现序列化 public static void SerializeStudent() throws IOException{ //1、序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("java基础\\oos.txt")); //2、创建student对象 Student student = new Student("张三",18); oos.writeObject(student); System.out.println("Student对象序列化成功"); //3、关闭流 oos.close(); }对象反序列化 public static Student DeserializeStudent() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("java基础\\oos.txt")); Student student = (Student) ois.readObject(); System.out.println("Student对象反序列化完成"); ois.close(); return student; }serialVersionUID的作用序列化对象未加serialVersionUID时,反序列化异常serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量 序列化版本ID的真实用途:当实体中增加属性后,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。在例子中,如果没有指定Person类的serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个序列化版本号不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。可以说serialVersionUID是序列化和反序列化之间彼此认识的唯一信物。IDEA设置自动生成serialVersionUID
2022年03月23日
76 阅读
0 评论
0 点赞
2022-03-21
实际使用数据库建表时varchar类型使用的区别
一直有纠结过一个问题,不知道其他同学有没有,实际开发中数据库字段类型varchar类型是最好用的,不会出现类型不符的异常;管它是int类型还是double、date类型都能当字符占用类型存储。这真的是一个“坏味道”要改一改了:1、从字段类型的执行效率上,int最高,varchar最低。例如状态类型字段,使用char或者varchar是不可取的,int类型更容易建立索引和进行检索,毕竟数字类型是数据库检索的基础,char类型的毕竟需要经过转换,而varchar就更复杂了,其排序不仅需要转换和计算,还需要访问和遵循数据库的排序规则(实际上char也需要排序规则),而消耗的资源也更大。2、占用空间大小不同例如用varchar 来存储年月日,那么需要10个字节,而date类型只需4个字节,而datetime类型也只需要8个字节,都小于varchar类型3、建立索引问题频繁改动的字段类型建议使用varchar。varchar类型的字段用来建立索引容易产生的索引碎片简单理解索引碎片是空间利用率不足SQL索引与碎片=>删除索引并重建这种方式并不好.在删除索引期间,索引不可用.会导致阻塞发生。而对于删除聚集索引,则会导致对应的非聚集索引重建两次(删除时重建,建立时再重建).虽然这种方法并不好,但是对于索引的整理最为有效=>使用DROP_EXISTING语句重建索引为了避免重建两次索引,使用DROP_EXISTING语句重建索引,因为这个语句是原子性的,不会导致非聚集索引重建两次,但同样的,这种方式也会造成阻塞=>如前面文章所示,使用ALTER INDEX REBUILD语句重建索引使用这个语句同样也是重建索引,但是通过动态重建索引而不需要卸载并重建索引.是优于前两种方法的,但依旧会造成阻塞。可以通过ONLINE关键字减少锁,但会造成重建时间加长.
2022年03月21日
113 阅读
0 评论
0 点赞
1
2
3
4