• 关于

    java t用法

    的搜索结果

问题

EDAS 的 Java 版本是哪个版本,我能够选择吗?

猫饭先生 2019-12-01 21:06:32 928 浏览量 回答数 0

回答

在5.1以及之前版本的MySQL中新建一个Table,可以这样执行:CREATE TABLE t (i INT) TYPE = MYISAM;或者CREATE TABLE t (i INT) ENGINE = MYISAM;在MySQL5.5版本中,用TYPE来指定存储引擎已经行不通,标准用法是ENGINE。其实早在MySQL的NN个版本之前,官方手册已经建议废弃TYPE而推荐使用ENGINE,确切说是从MySQL 4.0.18版本开始,用TYPE指定存储引擎的语法一直保留至MySQL5.1,也仅仅是为了兼容旧的数据库版本。从现在开始,TYPE已经被禁用,指定MySQL存储引擎的命令没有其他选择,必须使用ENGINE。而ofBiz ,apache-ofbiz-10.04frameworkentitysrcorgofbizentityjdbcDatabaseUtil.java 这个工具类生成的建表SQL,是用TYPE = 的。修改 DatabaseUtil.java 类即可

落地花开啦 2019-12-02 01:43:13 0 浏览量 回答数 0

回答

利用Dockerfile构建一个简单的java应用镜像,依赖环境比较简单,JDK,定制化的Tomcat(名为star-appserver)1、环境准备 ubuntu:14.04 docker : 1.4 jdk:jdk-8u31-linux-x64.gz tomcat : 7.0(star-appserver) 在/usr/local下创建目录:sms,将jdk-8u31-linux-x64.gz和star-appserver(此处为了简单,已包含应用)拷贝到此目录下,由于Docker在构建镜像时,需将Dockerfile所在目录传给Docker daemon作为构建上下文,所以此目录下应包含构建时所依赖的各种环境。 2、环境准备好后,在sms下创建Dockerfile(名字必须为Dockerfile)文件,内容如下 FROM ubuntu:latest MAINTAINER zhangjy #install JDK and TOMCAT ADD jdk-8u31-linux-x64.gz /usr/local/ ADD tomcat /usr/local/ #tomcat下为star-appserver,如果直接复制star-appserver,只会复制目录里边的内容,不会复制目录本身 ADD timezone /etc/ #启动脚本,用于从镜像启动容器时调用执行,见下面的ENTRYPOINT ADD onStart.sh /usr/local/ ENV JAVA_HOME=/usr/local/jdk1.8.0_31 CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar PATH=$PATH:$JAVA_HOME/bin RUN echo "JAVA_HOME=/usr/local/jdk1.8.0_31\nCALSSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar\nPATH=$PATH:$JAVA_HOME/bin" >> /etc/profile #start tomcat ENTRYPOINT ["/usr/local/onStart.sh"] 3、在sms下创建onStart.sh,并赋予执行权限,用于启动tomcat并输出日志(为了保证容器中有执行状态的进程,否则容器停止) #!/bin/bash /usr/local/star-appserver/bin/startup.sh tail -f /usr/local/star-appserver/logs/stariboss.log 4、在sms下执行命令,创建成功 $docker build -t zhangjy/starsms:v1 . 启动时,发现应用访问数据库报错:ORA-01882: timezone region not found,原因是JVM默认使用Ubuntu的/etc/timezone里配置的时区,查看timezone时区为Etc/UTC,再查看ORACLE数据库支持的时区:select * from V$TIMEZONE_NAMES发现没有,于是又在sms目录下创建了一个timezone文件,将时区配置成Asia/Shanghai,在Dockerfile中加入到镜像/etc/目录下 Dockerfile文件配置说明:FROM 表明基于哪个镜像创建 MAINTAINER 作者和邮箱 ADD 将目录或文件加入到镜像的某个目录,格式是ADD <源文件> <目标目录> RUN 有两种格式: RUN <command> (the command is run in a shell - /bin/sh -c - shell form) RUN ["executable", "param1", "param2"](exec form) 默认RUN后的命令是在/bin/sh下执行,像Ubuntu默认/bin/sh是指向/bin/dash,如果想使用/bin/bash,则可按如下方式 RUN ["/bin/bash","-c","source /etc/profile"] 但需注意,这种方式不能解析类似于$HOME的参数引用 ENV 设置环境变量,在镜像构建过程中和容器启动后均有效 CMD CMD在容器运行的时候提供一些命令及参数,用法如下: CMD ["executable","param1","param2"](exec form, this is the preferred form) CMD ["param1","param2"](as default parameters to ENTRYPOINT) CMD command param1 param2 (shell form) - 第一种用法:运行一个可执行的文件并提供参数。 - 第二种用法:为ENTRYPOINT指定参数,即为ENTRYPOINT指定命令的默认参数,通过docker run命令传过来的参数会将其覆盖 - 第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。 如指定: 1. CMD [“/bin/echo”, “this is a echo test ”] build后运行(假设镜像名为ec): 1. docker run ec 就会输出: this is a echo test 注意:如果在docker run命令后指定命令,如docker run ec echo 'test',会将CMD的命令覆盖。CMD的命令不能接收run传过来的参数,而ENTRYPOINT可以ENTRYPOINT 有两种用法 ENTRYPOINT ["executable", "param1", "param2"](the preferred exec form) ENTRYPOINT command param1 param2 (shell form) 第一种可以接收docker run命令传过来的参数(即使docker run传过来的是命令,也会被当做参数处理),如果想覆盖,可使用docker run ... --entrypoint <COMMAND>

51干警网 2019-12-02 01:34:58 0 浏览量 回答数 0

阿里云高校特惠,助力学生创业梦!0元体验,快速入门云计算!

学生动手场景应用,快速了解并掌握云服务器的各种新奇玩法!

问题

gson.fromJson(str, Class<T>)请问这个Class<T>我应该传什么作为参数?

rickqin 2019-12-01 20:18:33 1558 浏览量 回答数 2

问题

在Android 5.0和Android 6.0上膨胀类androidx.constraintlay

LiuWH 2020-01-18 10:09:50 0 浏览量 回答数 1

回答

根据设计,字符串保存Unicode文本,因此可以组合所有语言脚本。为此,该实现包含一个数组(字段名value),其中每个字符都是两个字节的UTF-16值。 您在Java类中遇到了一个和AFAIK唯一的傻点。 所示的拷贝构造函数是毫无意义的,因为字符串是不可变的对象,它们可以通过简单的赋值来共享。它是C ++继承的化石,也许与String实习有关。 进行复制是没有意义的。这对于内部char数组也适用,实际上可以通过引用来分配。(不是很重要)。 因此,以下内容显示了没有经验的Java用法: String s = new String(t); 在最新的Java版本中,String的值实际上可能是某种编码形式的字节数组,因此,懒惰地提供了chars。 回答来源:Stack Overflow

montos 2020-03-22 15:38:10 0 浏览量 回答数 0

问题

使用泛型构造子类的实例

游客5ltrhvc3ievgs 2020-03-28 11:09:11 4 浏览量 回答数 1

回答

字符串,是Java中最常用的一个数据类型了。 本文,也是对于Java中字符串相关知识的一个补充,主要来介绍一下字符串拼接相关的知识。本文基于jdk1.8.0_181。 字符串拼接 字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起。 我们都知道,String是Java中一个不可变的类,所以他一旦被实例化就无法被修改。 不可变类的实例一旦创建,其成员变量的值就不能被修改。这样设计有很多好处,比如可以缓存hashcode、使用更加便利以及更加安全等。 但是,既然字符串是不可变的,那么字符串拼接又是怎么回事呢? 字符串不变性与字符串拼接 其实,所有的所谓字符串拼接,都是重新生成了一个新的字符串。下面一段字符串拼接代码: String s = "abcd"; s = s.concat("ef"); 其实最后我们得到的s已经是一个新的字符串了。如下图  s中保存的是一个重新创建出来的String对象的引用。 那么,在Java中,到底如何进行字符串拼接呢?字符串拼接有很多种方式,这里简单介绍几种比较常用的。 使用+拼接字符串 在Java中,拼接字符串最简单的方式就是直接使用符号+来拼接。如: String wechat = "Hollis"; String introduce = "每日更新Java相关技术文章"; String hollis = wechat + "," + introduce; 这里要特别说明一点,有人把Java中使用+拼接字符串的功能理解为运算符重载。其实并不是,Java是不支持运算符重载的。这其实只是Java提供的一个语法糖。后面再详细介绍。 运算符重载:在计算机程序设计中,运算符重载(英语:operator overloading)是多态的一种。运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。 语法糖:语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。 concat 除了使用+拼接字符串之外,还可以使用String类中的方法concat方法来拼接字符串。如: String wechat = "Hollis"; String introduce = "每日更新Java相关技术文章"; String hollis = wechat.concat(",").concat(introduce); StringBuffer 关于字符串,Java中除了定义了一个可以用来定义字符串常量的String类以外,还提供了可以用来定义字符串变量的StringBuffer类,它的对象是可以扩充和修改的。 使用StringBuffer可以方便的对字符串进行拼接。如: StringBuffer wechat = new StringBuffer("Hollis"); String introduce = "每日更新Java相关技术文章"; StringBuffer hollis = wechat.append(",").append(introduce); StringBuilder 除了StringBuffer以外,还有一个类StringBuilder也可以使用,其用法和StringBuffer类似。如: StringBuilder wechat = new StringBuilder("Hollis"); String introduce = "每日更新Java相关技术文章"; StringBuilder hollis = wechat.append(",").append(introduce); StringUtils.join 除了JDK中内置的字符串拼接方法,还可以使用一些开源类库中提供的字符串拼接方法名,如apache.commons中提供的StringUtils类,其中的join方法可以拼接字符串。 String wechat = "Hollis"; String introduce = "每日更新Java相关技术文章"; System.out.println(StringUtils.join(wechat, ",", introduce)); 这里简单说一下,StringUtils中提供的join方法,最主要的功能是:将数组或集合以某拼接符拼接到一起形成新的字符串,如: String []list ={"Hollis","每日更新Java相关技术文章"}; String result= StringUtils.join(list,","); System.out.println(result); //结果:Hollis,每日更新Java相关技术文章 并且,Java8中的String类中也提供了一个静态的join方法,用法和StringUtils.join类似。 以上就是比较常用的五种在Java种拼接字符串的方式,那么到底哪种更好用呢?为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接呢?  (阿里巴巴Java开发手册中关于字符串拼接的规约) 使用+拼接字符串的实现原理 前面提到过,使用+拼接字符串,其实只是Java提供的一个语法糖, 那么,我们就来解一解这个语法糖,看看他的内部原理到底是如何实现的。 还是这样一段代码。我们把他生成的字节码进行反编译,看看结果。 String wechat = "Hollis"; String introduce = "每日更新Java相关技术文章"; String hollis = wechat + "," + introduce; 反编译后的内容如下,反编译工具为jad。 String wechat = "Hollis"; String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";//每日更新Java相关技术文章 String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString(); 通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。 那么也就是说,Java中的+对字符串的拼接,其实现原理是使用StringBuilder.append。 concat是如何实现的 我们再来看一下concat方法的源代码,看一下这个方法又是如何实现的。 public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } 这段代码首先创建了一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使用这个字符数组创建一个新的String对象并返回。 通过源码我们也可以看到,经过concat方法,其实是new了一个新的String,这也就呼应到前面我们说的字符串的不变性问题上了。 StringBuffer和StringBuilder 接下来我们看看StringBuffer和StringBuilder的实现原理。 和String类类似,StringBuilder类也封装了一个字符数组,定义如下: char[] value; 与String不同的是,它并不是final的,所以他是可以修改的。另外,与String不同,字符数组中不一定所有位置都已经被使用,它有一个实例变量,表示数组中已经使用的字符个数,定义如下: int count; 其append源码如下: public StringBuilder append(String str) { super.append(str); return this; } 该类继承了AbstractStringBuilder类,看下其append方法: public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; } append会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展。 StringBuffer和StringBuilder类似,最大的区别就是StringBuffer是线程安全的,看一下StringBuffer的append方法。 public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } 该方法使用synchronized进行声明,说明是一个线程安全的方法。而StringBuilder则不是线程安全的。 StringUtils.join是如何实现的 通过查看StringUtils.join的源代码,我们可以发现,其实他也是通过StringBuilder来实现的。 public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { if (array == null) { return null; } if (separator == null) { separator = EMPTY; } // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) // (Assuming that all Strings are roughly equally long) final int noOfItems = endIndex - startIndex; if (noOfItems <= 0) { return EMPTY; } final StringBuilder buf = new StringBuilder(noOfItems * 16); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); } if (array[i] != null) { buf.append(array[i]); } } return buf.toString(); } 效率比较 既然有这么多种字符串拼接的方法,那么到底哪一种效率最高呢?我们来简单对比一下。 long t1 = System.currentTimeMillis(); //这里是初始字符串定义 for (int i = 0; i < 50000; i++) { //这里是字符串拼接代码 } long t2 = System.currentTimeMillis(); System.out.println("cost:" + (t2 - t1)); 我们使用形如以上形式的代码,分别测试下五种字符串拼接代码的运行时间。得到结果如下: + cost:5119 StringBuilder cost:3 StringBuffer cost:4 concat cost:3623 StringUtils.join cost:25726 从结果可以看出,用时从短到长的对比是: StringBuilder<StringBuffer<concat<+<StringUtils.join StringBuffer在StringBuilder的基础上,做了同步处理,所以在耗时上会相对多一些。 StringUtils.join也是使用了StringBuilder,并且其中还是有很多其他操作,所以耗时较长,这个也容易理解。其实StringUtils.join更擅长处理字符串数组或者列表的拼接。 那么问题来了,前面我们分析过,其实使用+拼接字符串的实现原理也是使用的StringBuilder,那为什么结果相差这么多,高达1000多倍呢? 我们再把以下代码反编译下: long t1 = System.currentTimeMillis(); String str = "hollis"; for (int i = 0; i < 50000; i++) { String s = String.valueOf(i); str += s; } long t2 = System.currentTimeMillis(); System.out.println("+ cost:" + (t2 - t1)); 反编译后代码如下: long t1 = System.currentTimeMillis(); String str = "hollis"; for(int i = 0; i < 50000; i++) { String s = String.valueOf(i); str = (new StringBuilder()).append(str).append(s).toString(); } long t2 = System.currentTimeMillis(); System.out.println((new StringBuilder()).append("+ cost:").append(t2 - t1).toString()); 我们可以看到,反编译后的代码,在for循环中,每次都是new了一个StringBuilder,然后再把String转成StringBuilder,再进行append。 而频繁的新建对象当然要耗费很多时间了,不仅仅会耗费时间,频繁的创建对象,还会造成内存资源的浪费。 所以,阿里巴巴Java开发手册建议:循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。而不要使用+。 总结 本文介绍了什么是字符串拼接,虽然字符串是不可变的,但是还是可以通过新建字符串的方式来进行字符串的拼接。 常用的字符串拼接方式有五种,分别是使用+、使用concat、使用StringBuilder、使用StringBuffer以及使用StringUtils.join。 由于字符串拼接过程中会创建新的对象,所以如果要在一个循环体中进行字符串拼接,就要考虑内存问题和效率问题。 因此,经过对比,我们发现,直接使用StringBuilder的方式是效率最高的。因为StringBuilder天生就是设计来定义可变字符串和字符串的变化操作的。 但是,还要强调的是: 1、如果不是在循环体中进行字符串拼接的话,直接使用+就好了。 2、如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder。

montos 2020-06-01 21:30:32 0 浏览量 回答数 0

问题

Eclipse Xtend对Java说:我帮你瘦身:报错

kun坤 2020-06-09 15:18:52 3 浏览量 回答数 1

回答

注意看 jfinal 手册, dao 对象不能用于 update、save,只能用于查询,上面的代码直接使用 t_activeiti.save() 即可   此外,可以直接使用 getModel 或 getBean 来接收参数,不需要一个一个的 getPara(...) 太多代码冗余 ######页面我传的值,有些是来做判断的,但是用了getModel就必须在数据库对应的表里 添加这个字段######我好像知道了,getModel(Blog.class, “”);。jfinal这个getModel映射有点“强行”的味道,如果我页面提交了值,那么数据库所对应的表,就必须要有对应的字段。不是那种只映射有值的数据样?###### 在 jfinal 官网下载 jfinal demo,里面有 dao 的用法,在此下载:http://www.jfinal.com######我这个是从ajax,上面传过来的,不是通过表单。用getModel得不到######回复 @JFinal : 谢谢了啊######吐槽这样的命名,数据库、java命名简直一团糟!中西合璧这不比治疗效果啊。内面类别“NMLB”逗逗来吧“DDLB”这样就呵呵,理解错了就恼火了哈哈…… 另外,Map是把双刃剑,属性名老重复写感觉就恶心,java不像动态语言可以直接obj.attr Map随意,但也不好维护。 推荐你去看看阿里巴巴java规范文档。######回复 @蓝水晶飞机 : 谢谢指教

爱吃鱼的程序员 2020-06-03 16:42:27 0 浏览量 回答数 0

回答

 可能是gson在转换时类型没有处理好,建议使用jfinal官方提供的Jackson或者FastJson来处理,大至用法是: //Target对象转json字符串StringjsonStr=Jackson.getJson().toJson(target);//json字符串转Target对象Targett=Jsonson.getSjon().parse(jsonStr,Target.class);  注意引入相关的包,要引入的包参考一下jfinal项目的pom.xml,去掉provide标签,另外要特别注意,json字符串转成对象,需要setter方法的支持,如果使用的是jfinal的model,可以用jfinal提供的generator生成带有setter方法的model谢谢,使用了 FastJson,现在可以了。 按照面向对象的规矩, 操作这个object的方法应该要封装起来, 单纯的JSONObject不能封装JAVA调用的函数, 那自然是写个javabean用来封装了, JSONObject转成javabean就可以用了,具体操作参考: http://edu.51cto.com/course/course_id-4220.htmlspringmvc+restful直接传对象 importcom.alibaba.fastjson.JSONObject; publicclassbean{ publicstatic<T>TJsonToBean(StringJsonString,Class<T>clazz){ return(T)JSONObject.toJavaObject(JSONObject.parseObject(JsonString),clazz); } }

爱吃鱼的程序员 2020-06-09 16:15:33 0 浏览量 回答数 0

问题

流使用功能编程

montos 2020-03-25 13:44:52 2 浏览量 回答数 1

回答

将参数中的List返回一个不可修改的List Collections的静态方法unmodifiableList可以达到目的。方法原型为:public static List unmodifiableList(List<? extends T> list);用法也很简单,传入一个List实例la,返回这个list的只读视图lb,类型依然是List。之后对lb进行add、remove等改变其内容的操作将导致编译不通过。 https://blog.csdn.net/cilen/article/details/7744969 Student1类,仅对外提供的getCourses()方法,而没有setCourses()方法,而且 通过getCourses()方法获得的courses是“只读的”,如果你试图向其添加一个新课程,则 抛出java.lang.UnsupportedOperationException。你必须通过Student1.addCourse()来 向特定的Student1对象添加一个新课程。就好像,你必须让顾客自己向购物车里放食物, 而不能在顾客毫不知情下,偷偷向其购物车里放食物。

问问小秘 2020-01-03 13:51:25 0 浏览量 回答数 0

问题

Db.queryInt用法请教~ 400 请求报错 

kun坤 2020-05-29 16:30:23 0 浏览量 回答数 1

问题

异步操作校验工具awaitiliy源码分析

福利达人 2019-12-01 21:21:16 2525 浏览量 回答数 0

回答

没玩过这些,我直接说一下我们公司内部架构的用法把,主要给你讲一下事务 什么叫做事务,不知道你用的是啥数据库,事务就是当前链接下的数据要保持一致性,也就是你上面的所谓的session,我只用Oracle数据库,如果你用过pl/sql的话你每打开一个COMMANDWINDOW他就是一个事务,当前的COMMANDWINDOW做一个数据的增,删,改,如果不提交的话,那么另外一个COMMANDWINDOW里是看不出数据的变化了的,如果需要在另外一个里面看得到数据变化,那么你需要提交事务,使用commit语句,关闭COMMANDWINDOW也就是释放事务 上面的一段配合的只是这么几句代码,我以最简单的JDBC为例 conn=DriverManager.getConnection("jdbc:mysql:///day11","root","root");//获取链接conn.setAutoCommit(false);//开启事务conn.commit();//事务提交conn.rollback();//事务回滚conn.close();//这里是关闭连接 你这里的疑问,我没玩过hibernet,但是大同小异,我以我 公司的内部框架的代码逻辑为例: 如果我是新开启一个事务,也就是你说的 opensession,那么就是新开启一个事务,如果我选择的是获取当前的事务,就是你这边的 getcurrentsession,那么我会做一下判断,当前的线程是否存在事务,如果不存在,我就会新建一个事务,而从你的这个报错看的很清楚,hibernate的获取当前事务的时候,如果不存在当前事务,那么他就直接报错了! ------菜鸟见解,欢迎拍砖,PS:JDBC的事务控制,回答这个问题的时候我才去百度,以前就一直是记JDBC五步操作,到公司直接用内部框架了,就没去认真研究! 不要狭义的理解session就是你想的那个session哈 getcurrentsession当前线程的session为了让pojo从数据库到页面到结束使用出于同一session便于hibernate代理,并添加各种操作,事务等保证状态一致, opensession开启一个新session,没有上述特点 spring其实在后面代理了你的hibernate动作,模板保证每个写操作[你配置的情况下]都有事务控制,保证数据一致性[出现异常,事务回滚] 首先明确一点,关系数据库中的事务,核心配置在DB中的由DBA设置,我们在JAVA层的操作准确的说是事务传播属性 首先说一下关系数据库中的事务特性 事务的 特性(ACID特性) A:原子性(Atomicity)    事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。B:一致性(Consistency)    事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。C:隔离性(Isolation)   一个事务的执行不能被其他事务干扰。D:持续性/永久性(Durability)   一个事务一旦提交,它对数据库中数据的改变就应该是永久性的 然后在事务中存在的问题准确的说是有一些根据不同的隔离级别或业务要求是允许的 1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。 引用来自“卧枝会中田”的评论 首先明确一点,关系数据库中的事务,核心配置在DB中的由DBA设置,我们在JAVA层的操作准确的说是事务传播属性 首先说一下关系数据库中的事务特性 事务的 特性(ACID特性) A:原子性(Atomicity)    事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。B:一致性(Consistency)    事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。C:隔离性(Isolation)   一个事务的执行不能被其他事务干扰。D:持续性/永久性(Durability)   一个事务一旦提交,它对数据库中数据的改变就应该是永久性的 然后在事务中存在的问题准确的说是有一些根据不同的隔离级别或业务要求是允许的 1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。

爱吃鱼的程序员 2020-06-12 15:51:30 0 浏览量 回答数 0

问题

【阿里云产品公测】简单日志服务SLS使用评测含教程

mr_wid 2019-12-01 21:08:11 36639 浏览量 回答数 20

问题

MaxCompute最佳实践:修改不兼容SQL实战

行者武松 2019-12-01 22:09:22 4078 浏览量 回答数 0

问题

EMR 常见问题?

nicenelly 2019-12-01 21:19:58 2355 浏览量 回答数 0

回答

如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。 很多人都对其中的一些概念不够明确,如同步、并发等等,让我们先建立一个数据字典,以免产生误会。 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程 并行与并发: 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。 并发与并行 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码: void transferMoney(User from, User to, float amount){ to.setMoney(to.getBalance() + amount); from.setMoney(from.getBalance() - amount); } 同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。 好了,让我们开始吧。我准备分成几部分来总结涉及到多线程的内容: 扎好马步:线程的状态 内功心法:每个对象都有的方法(机制) 太祖长拳:基本线程类 九阴真经:高级多线程控制类 扎好马步:线程的状态 先来两张图: 线程状态 线程状态转换 各种状态一目了然,值得一提的是"blocked"这个状态:线程在Running的过程中可能会遇到阻塞(Blocked)情况 调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。 调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable) 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。 此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。内功心法:每个对象都有的方法(机制) synchronized, wait, notify 是任何对象都具有的同步工具。让我们先来了解他们 monitor 他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。 wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。 当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。 再讲用法: synchronized单独使用: 代码块:如下,在多线程环境下,synchronized块中的方法获取了lock实例的monitor,如果实例相同,那么只有一个线程能执行该块内容 复制代码 public class Thread1 implements Runnable { Object lock; public void run() { synchronized(lock){ ..do something } } } 复制代码 直接用于方法: 相当于上面代码中用lock来锁定的效果,实际获取的是Thread1类的monitor。更进一步,如果修饰的是static方法,则锁定该类所有实例。 public class Thread1 implements Runnable { public synchronized void run() { ..do something } } synchronized, wait, notify结合:典型场景生产者消费者问题 复制代码 /** * 生产者生产出来的产品交给店员 */ public synchronized void produce() { if(this.product >= MAX_PRODUCT) { try { wait(); System.out.println("产品已满,请稍候再生产"); } catch(InterruptedException e) { e.printStackTrace(); } return; } this.product++; System.out.println("生产者生产第" + this.product + "个产品."); notifyAll(); //通知等待区的消费者可以取出产品了 } /** * 消费者从店员取产品 */ public synchronized void consume() { if(this.product <= MIN_PRODUCT) { try { wait(); System.out.println("缺货,稍候再取"); } catch (InterruptedException e) { e.printStackTrace(); } return; } System.out.println("消费者取走了第" + this.product + "个产品."); this.product--; notifyAll(); //通知等待去的生产者可以生产产品了 } 复制代码 volatile 多线程的内存模型:main memory(主存)、working memory(线程栈),在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。 volatile 针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。太祖长拳:基本线程类 基本线程类指的是Thread类,Runnable接口,Callable接口Thread 类实现了Runnable接口,启动一个线程的方法:  MyThread my = new MyThread();  my.start(); Thread类相关方法:复制代码 //当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)public static Thread.yield() //暂停一段时间public static Thread.sleep() //在一个线程中调用other.join(),将等待other执行完后才继续本线程。    public join()//后两个函数皆可以被打断public interrupte() 复制代码 关于中断:它并不像stop方法那样会中断一个正在运行的线程。线程会不时地检测中断标识位,以判断线程是否应该被中断(中断标识值是否为true)。终端只会影响到wait状态、sleep状态和join状态。被打断的线程会抛出InterruptedException。Thread.interrupted()检查当前线程是否发生中断,返回booleansynchronized在获锁的过程中是不能被中断的。 中断是一个状态!interrupt()方法只是将这个状态置为true而已。所以说正常运行的程序不去检测状态,就不会终止,而wait等阻塞方法会去检查并抛出异常。如果在正常运行的程序中添加while(!Thread.interrupted()) ,则同样可以在中断后离开代码体 Thread类最佳实践:写的时候最好要设置线程名称 Thread.name,并设置线程组 ThreadGroup,目的是方便管理。在出现问题的时候,打印线程栈 (jstack -pid) 一眼就可以看出是哪个线程出的问题,这个线程是干什么的。 如何获取线程中的异常 不能用try,catch来获取线程中的异常Runnable 与Thread类似Callable future模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态 ExecutorService e = Executors.newFixedThreadPool(3); //submit方法有多重参数版本,及支持callable也能够支持runnable接口类型.Future future = e.submit(new myCallable());future.isDone() //return true,false 无阻塞future.get() // return 返回值,阻塞直到该线程运行结束 九阴真经:高级多线程控制类 以上都属于内功心法,接下来是实际项目中常用到的工具了,Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者编写高效、易维护、结构清晰的Java多线程程序。1.ThreadLocal类 用处:保存线程的独立变量。对一个线程类(继承自Thread)当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。 实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。主要方法是get()和set(T a),set之后在map里维护一个threadLocal -> a,get时将a返回。ThreadLocal是一个特殊的容器。2.原子类(AtomicInteger、AtomicBoolean……) 如果使用atomic wrapper class如atomicInteger,或者使用自己保证原子的操作,则等同于synchronized //返回值为booleanAtomicInteger.compareAndSet(int expect,int update) 该方法可用于实现乐观锁,考虑文中最初提到的如下场景:a给b付款10元,a扣了10元,b要加10元。此时c给b2元,但是b的加十元代码约为:复制代码 if(b.value.compareAndSet(old, value)){ return ;}else{ //try again // if that fails, rollback and log} 复制代码 AtomicReference对于AtomicReference 来讲,也许对象会出现,属性丢失的情况,即oldObject == current,但是oldObject.getPropertyA != current.getPropertyA。这时候,AtomicStampedReference就派上用场了。这也是一个很常用的思路,即加上版本号3.Lock类  lock: 在java.util.concurrent包内。共有三个实现: ReentrantLockReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLock 主要目的是和synchronized一样, 两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。 区别如下:复制代码 lock更灵活,可以自由定义多把锁的枷锁解锁顺序(synchronized要按照先加的后解顺序)提供多种加锁方案,lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, 还有trylock的带超时时间版本。本质上和监视器锁(即synchronized是一样的)能力越大,责任越大,必须控制好加锁和解锁,否则会导致灾难。和Condition类的结合。性能更高,对比如下图: 复制代码 synchronized和Lock性能对比 ReentrantLock    可重入的意义在于持有锁的线程可以继续持有,并且要释放对等的次数后才真正释放该锁。使用方法是: 1.先new一个实例 static ReentrantLock r=new ReentrantLock(); 2.加锁       r.lock()或r.lockInterruptibly(); 此处也是个不同,后者可被打断。当a线程lock后,b线程阻塞,此时如果是lockInterruptibly,那么在调用b.interrupt()之后,b线程退出阻塞,并放弃对资源的争抢,进入catch块。(如果使用后者,必须throw interruptable exception 或catch)     3.释放锁    r.unlock() 必须做!何为必须做呢,要放在finally里面。以防止异常跳出了正常流程,导致灾难。这里补充一个小知识点,finally是可以信任的:经过测试,哪怕是发生了OutofMemoryError,finally块中的语句执行也能够得到保证。 ReentrantReadWriteLock 可重入读写锁(读写锁的一个实现)   ReentrantReadWriteLock lock = new ReentrantReadWriteLock()  ReadLock r = lock.readLock();  WriteLock w = lock.writeLock(); 两者都有lock,unlock方法。写写,写读互斥;读读不互斥。可以实现并发读的高效线程安全代码4.容器类 这里就讨论比较常用的两个: BlockingQueueConcurrentHashMap BlockingQueue阻塞队列。该类是java.util.concurrent包下的重要类,通过对Queue的学习可以得知,这个queue是单向队列,可以在队列头添加元素和在队尾删除或取出元素。类似于一个管  道,特别适用于先进先出策略的一些应用场景。普通的queue接口主要实现有PriorityQueue(优先队列),有兴趣可以研究 BlockingQueue在队列的基础上添加了多线程协作的功能: BlockingQueue 除了传统的queue功能(表格左边的两列)之外,还提供了阻塞接口put和take,带超时功能的阻塞接口offer和poll。put会在队列满的时候阻塞,直到有空间时被唤醒;take在队 列空的时候阻塞,直到有东西拿的时候才被唤醒。用于生产者-消费者模型尤其好用,堪称神器。 常见的阻塞队列有: ArrayListBlockingQueueLinkedListBlockingQueueDelayQueueSynchronousQueue ConcurrentHashMap高效的线程安全哈希map。请对比hashTable , concurrentHashMap, HashMap5.管理类 管理类的概念比较泛,用于管理线程,本身不是多线程的,但提供了一些机制来利用上述的工具做一些封装。了解到的值得一提的管理类:ThreadPoolExecutor和 JMX框架下的系统级管理类 ThreadMXBeanThreadPoolExecutor如果不了解这个类,应该了解前面提到的ExecutorService,开一个自己的线程池非常方便:复制代码 ExecutorService e = Executors.newCachedThreadPool(); ExecutorService e = Executors.newSingleThreadExecutor(); ExecutorService e = Executors.newFixedThreadPool(3); // 第一种是可变大小线程池,按照任务数来分配线程, // 第二种是单线程池,相当于FixedThreadPool(1) // 第三种是固定大小线程池。 // 然后运行 e.execute(new MyRunnableImpl()); 复制代码 该类内部是通过ThreadPoolExecutor实现的,掌握该类有助于理解线程池的管理,本质上,他们都是ThreadPoolExecutor类的各种实现版本。请参见javadoc: ThreadPoolExecutor参数解释 翻译一下:复制代码 corePoolSize:池内线程初始值与最小值,就算是空闲状态,也会保持该数量线程。maximumPoolSize:线程最大值,线程的增长始终不会超过该值。keepAliveTime:当池内线程数高于corePoolSize时,经过多少时间多余的空闲线程才会被回收。回收前处于wait状态unit:时间单位,可以使用TimeUnit的实例,如TimeUnit.MILLISECONDS workQueue:待入任务(Runnable)的等待场所,该参数主要影响调度策略,如公平与否,是否产生饿死(starving)threadFactory:线程工厂类,有默认实现,如果有自定义的需要则需要自己实现ThreadFactory接口并作为参数传入。 阿里云优惠券地址https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=nb3paa5b

景凌凯 2019-12-02 01:40:35 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:30 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:30 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 适用场景 表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例: 不使用表单上传 表单上传 流程对比 网站用户上传简历。 网站服务器回应上传页面。 简历被上传到网站服务器。 网站服务器再将简历上传到OSS。 网站用户上传简历。 网站服务器回应上传页面。 简历上传到OSS。 上传限制 大小限制:使用表单上传时,Object不能超过5GB。 命名限制: 使用UTF-8编码。 长度必须在1–1023字节之间。 不能以正斜线(/)或者反斜线(\)字符开头。 优势 从流程上来说,少了一步转发,更加方便。 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS。上传量过大时,压力都在OSS上,由OSS来保障服务质量。 安全及授权 为防止第三方未经授权向开发者的Bucket上传Object,OSS提供了Bucket和Object级别的访问权限控制,详情请参见OSS细粒度的权限控制。 为了授权给第三方上传,使用的是PostPolicy方法,详情请参见PostObject。 使用表单上传的基本步骤 构建一个Post Policy。 Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名字等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参考Post Policy。 例如如下Policy,网站用户能上传的过期时间是2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),能上传的文件最大为104857600字节。 以Python代码为例子,Policy是json格式的字符串。 policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}" 将Policy字符串进行base64编码。 用OSS的AccessKeySecret对base64编码后的Policy进行签名。 构建上传的HTML页面。 打开HTML页面,选择文件上传。 完整Python代码示例: #coding=utf8 import md5 import hashlib import base64 import hmac from optparse import OptionParser def convert_base64(input): return base64.b64encode(input) def get_sign_policy(key, policy): return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest()) def get_form(bucket, endpoint, access_key_id, access_key_secret, out): #1 构建一个Post Policy policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}" print("policy: %s" % policy) #2 将Policy字符串进行base64编码 base64policy = convert_base64(policy) print("base64_encode_policy: %s" % base64policy) #3 用OSS的AccessKeySecret对编码后的Policy进行签名 signature = get_sign_policy(access_key_secret, base64policy) #4 构建上传的HTML页面 form = ''' <html> <meta http-equiv=content-type content="text/html; charset=UTF-8"> <head><title>OSS表单上传(PostObject)</title></head> <body> <form action="http://%s.%s" method="post" enctype="multipart/form-data"> <input type="text" name="OSSAccessKeyId" value="%s"> <input type="text" name="policy" value="%s"> <input type="text" name="Signature" value="%s"> <input type="text" name="key" value="upload/${filename}"> <input type="text" name="success_action_redirect" value="http://oss.aliyun.com"> <input type="text" name="success_action_status" value="201"> <input name="file" type="file" id="file"> <input name="submit" value="Upload" type="submit"> </form> </body> </html> ''' % (bucket, endpoint, access_key_id, base64policy, signature) f = open(out, "wb") f.write(form) f.close() print("form is saved into %s" % out) if __name__ == '__main__': parser = OptionParser() parser.add_option("", "--bucket", dest="bucket", help="specify ") parser.add_option("", "--endpoint", dest="endpoint", help="specify") parser.add_option("", "--id", dest="id", help="access_key_id") parser.add_option("", "--key", dest="key", help="access_key_secret") parser.add_option("", "--out", dest="out", help="out put form") (opts, args) = parser.parse_args() if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out: get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out) else: print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__ 将此段代码保存为post_object.py,然后用python post_object.py来运行。 用法: python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名 示例: python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html 说明 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201。可以替换。 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。 功能使用参考 API:PostObject Java SDK:表单上传 最佳实践 Web端直传实践 跨域资源共享(CORS)

2019-12-01 23:12:30 0 浏览量 回答数 0

回答

java飘过,用过JNA,int 和指针都是32位的。SO......######指针里面存的就是一个内存地址,内存地址就可以用一个整数来表示。so……c忘光了######指针是一个地址,而且是32位,和int类型一样,在机器中表现的就是一个“数字”而已######太官方啦,有木有别的解释, return (void* )1 是什么意思,这个1代表什么?内存?######(void ) -1 代表什么意思?  ######(void)-1 表示把-1转换为一个无类型指针,这个指针存储的值就是-1. 看看关于C和指针方面的书,这都是比较基础的######void代表的是void type而不是void value######都是void了怎么还能存-1呢?######哈。首先要明确,机器处理的对象就是数字。当然不同位宽的数字有不同的辅助操作。而核心操作基本上就是加(减),乘,位操作,和取址操作。比较操作其实可以等同为减操作。 除非有硬件除法器,否则是没有除的概念。除法是调用系统库运算的结果。 由于核心操作都一样,所以不同类型,无非是位宽和核心操作前辅助操作的差异而已。 高级语言是为了方便你,帮你约束各个位宽,而落在机器上没有本质差异。 指针类型,无论指向的地址类型是什么 ,都是一个类型,就是“指针”类型。这个和机器的地址宽度有关。有时不和总线地址宽度有关,主要看CPU内部怎么处理了。但对于一个具体平台和OS,指针类型的位宽都是一致的。 需要注意的是,只有int和指针类型的位宽相同时,强制的转换才没有问题。否则还是会报错。int不等于指针类型的位宽。只是碰巧32位如此。###### 引用来自“中山野鬼”的答案 哈。首先要明确,机器处理的对象就是数字。当然不同位宽的数字有不同的辅助操作。而核心操作基本上就是加(减),乘,位操作,和取址操作。比较操作其实可以等同为减操作。 除非有硬件除法器,否则是没有除的概念。除法是调用系统库运算的结果。 由于核心操作都一样,所以不同类型,无非是位宽和核心操作前辅助操作的差异而已。 高级语言是为了方便你,帮你约束各个位宽,而落在机器上没有本质差异。 指针类型,无论指向的地址类型是什么 ,都是一个类型,就是“指针”类型。这个和机器的地址宽度有关。有时不和总线地址宽度有关,主要看CPU内部怎么处理了。但对于一个具体平台和OS,指针类型的位宽都是一致的。 需要注意的是,只有int和指针类型的位宽相同时,强制的转换才没有问题。否则还是会报错。int不等于指针类型的位宽。只是碰巧32位如此。 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <string.h> struct stu                            //我自己定义的学生结构 { char name[20]; int age; }; void* thr_fn1(void* arg)                //线程thr_fn1 {    printf("thread 1 exiting\n");     printf("%d\n", ((struct stu*)arg)->age);        //把void* arg准换为结构体的指针,取出age成员    //((char*)arg)[20], ((int*)arg)[5] 用这样也可以读name , age return (void* )1; }     int main(void) 42 { 43 struct stu ones; 44 struct stu* pones = &ones; 45 memcpy(ones.name, "sgc", 4); 46 ones.age =10; 47 48 pthread_t tid; 49 void* tret; 50 pthread_create(&tid, NULL, thr_fn1, (void*)pones);    //创建线程1,传入结构体的指针并转换为void* 51 pthread_join(tid, &tret);                             //等待线程1结束        return 0;   } 我又不懂, void* 的一般用法有哪些,都在什么地方用? ###### 引用来自“gcshang”的答案 引用来自“中山野鬼”的答案 哈。首先要明确,机器处理的对象就是数字。当然不同位宽的数字有不同的辅助操作。而核心操作基本上就是加(减),乘,位操作,和取址操作。比较操作其实可以等同为减操作。 除非有硬件除法器,否则是没有除的概念。除法是调用系统库运算的结果。 由于核心操作都一样,所以不同类型,无非是位宽和核心操作前辅助操作的差异而已。 高级语言是为了方便你,帮你约束各个位宽,而落在机器上没有本质差异。 指针类型,无论指向的地址类型是什么 ,都是一个类型,就是“指针”类型。这个和机器的地址宽度有关。有时不和总线地址宽度有关,主要看CPU内部怎么处理了。但对于一个具体平台和OS,指针类型的位宽都是一致的。 需要注意的是,只有int和指针类型的位宽相同时,强制的转换才没有问题。否则还是会报错。int不等于指针类型的位宽。只是碰巧32位如此。 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <string.h> struct stu                            //我自己定义的学生结构 { char name[20]; int age; }; void* thr_fn1(void* arg)                //线程thr_fn1 {    printf("thread 1 exiting\n");     printf("%d\n", ((struct stu*)arg)->age);        //把void* arg准换为结构体的指针,取出age成员    //((char*)arg)[20], ((int*)arg)[5] 用这样也可以读name , age return (void* )1; }     int main(void) 42 { 43 struct stu ones; 44 struct stu* pones = &ones; 45 memcpy(ones.name, "sgc", 4); 46 ones.age =10; 47 48 pthread_t tid; 49 void* tret; 50 pthread_create(&tid, NULL, thr_fn1, (void*)pones);    //创建线程1,传入结构体的指针并转换为void* 51 pthread_join(tid, &tret);                             //等待线程1结束        return 0;   } 我又不懂, void* 的一般用法有哪些,都在什么地方用? void 只要你觉得这个不知道啥类型 你就可以用void ###### 引用来自“小耶果”的答案 (void*)-1 表示把-1转换为一个无类型指针,这个指针存储的值就是-1. 看看关于C和指针方面的书,这都是比较基础的  #include <stdio.h> 02    #include <stdlib.h> 03    #include <pthread.h> 04    #include <unistd.h> 05    #include <string.h> 06      07    struct stu                            //我自己定义的学生结构 08    { 09        char name[20]; 10        int age; 11    }; 12    void* thr_fn1(void* arg)                //线程thr_fn1 13    { 14      15        printf("thread 1 exiting\n"); 16        printf("%d\n", ((struct stu*)arg)->age);        //把void* arg准换为结构体的指针,取出age成员 17      18       //((char*)arg)[20], ((int*)arg)[5]  用这样也可以读name , age 19       return (void* )1; 20      21    } 22        int main(void) 23     { 24         struct stu ones; 25         struct stu* pones = &ones; 26         memcpy(ones.name, "sgc", 4); 27         ones.age =10; 28      29         pthread_t tid; 30         void* tret; 31         pthread_create(&tid, NULL, thr_fn1, (void*)pones);    //创建线程1,传入结构体的指针并转换为void* 32         pthread_join(tid, &tret);                             //等待线程1结束 33     } 你看我把指向结构体的指针pones转换为void*传入到线程thr_fn1的函数中,然后再函数中把void* 的指针转换为 结构体指针,然后访问结构体成员是否有问题?void*的典型用法是怎样的 ?

kun坤 2020-05-29 11:40:27 0 浏览量 回答数 0

回答

Linux这么多命令,通常会让初学者望而生畏。下面是我结合日常工作,以及在公司的内部培训中,针对对Linux不是很熟悉的同学,精选的一批必须要搞懂的命令集合。 任何一个命令其实都是可以深入的,比如tail -f和tail -F的区别。我们不去关心,只使用最常见的示例来说明。本文不会教你具体的用法,那是抢man命令的饭碗。这只是个引导篇,力求简洁。 学习方式:多敲多打,用条件反射替代大脑记忆—如果你将来或者现在要用它来吃饭的话。其中,也有一些难啃的骨头,关注小姐姐味道微信公众号,我们一起用锋利的牙齿,来把它嚼碎。 内容: ✔ 目录操作 ✔ 文本处理 ✔ 压缩 ✔ 日常运维 ✔ 系统状态概览 ✔ 工作常用 目录操作 工作中,最常打交道的就是对目录和文件的操作。linux提供了相应的命令去操作他,并将这些命令抽象、缩写。 基本操作 可能是这些命令太常用了,多打一个字符都是罪过。所以它们都很短,不用阿拉伯数字,一个剪刀手就能数过来。 看命令。 mkdir 创建目录 make dir cp 拷贝文件 copy mv 移动文件 move rm 删除文件 remove 例子: # 创建目录和父目录a,b,c,d mkdir -p a/b/c/d # 拷贝文件夹a到/tmp目录 cp -rvf a/ /tmp/ # 移动文件a到/tmp目录,并重命名为b mv -vf a /tmp/b # 删除机器上的所有文件 rm -rvf / 漫游 linux上是黑漆漆的命令行,依然要面临人生三问:我是谁?我在哪?我要去何方? ls 命令能够看到当前目录的所有内容。ls -l能够看到更多信息,判断你是谁。 pwd 命令能够看到当前终端所在的目录。告诉你你在哪。 cd 假如你去错了地方,cd命令能够切换到对的目录。 find find命令通过筛选一些条件,能够找到已经被遗忘的文件。 至于要去何方,可能就是主宰者的意志了。 文本处理 这是是非常非常加分的技能。get到之后,也能节省更多时间来研究面向对象。 查看文件 cat 最常用的就是cat命令了,注意,如果文件很大的话,cat命令的输出结果会疯狂在终端上输出,可以多次按ctrl+c终止。 # 查看文件大小 du -h file # 查看文件内容 cat file less 既然cat有这个问题,针对比较大的文件,我们就可以使用less命令打开某个文件。 类似vim,less可以在输入/后进入查找模式,然后按n(N)向下(上)查找。 有许多操作,都和vim类似,你可以类比看下。 tail 大多数做服务端开发的同学,都了解这么命令。比如,查看nginx的滚动日志。 tail -f access.log tail命令可以静态的查看某个文件的最后n行,与之对应的,head命令查看文件头n行。但head没有滚动功能,就像尾巴是往外长的,不会反着往里长。 tail -n100 access.log head -n100 access.log 统计 sort和uniq经常配对使用。 sort可以使用-t指定分隔符,使用-k指定要排序的列。 下面这个命令输出nginx日志的ip和每个ip的pv,pv最高的前10 #2019-06-26T10:01:57+08:00|nginx001.server.ops.pro.dc|100.116.222.80|10.31.150.232:41021|0.014|0.011|0.000|200|200|273|-|/visit|sign=91CD1988CE8B313B8A0454A4BBE930DF|-|-|http|POST|112.4.238.213 awk -F"|" '{print $3}' access.log | sort | uniq -c | sort -nk1 -r | head -n10 其他 grep grep用来对内容进行过滤,带上--color参数,可以在支持的终端可以打印彩色,参数n则输出具体的行数,用来快速定位。 比如:查看nginx日志中的POST请求。 grep -rn --color POST access.log 推荐每次都使用这样的参数。 如果我想要看某个异常前后相关的内容,就可以使用ABC参数。它们是几个单词的缩写,经常被使用。 A after 内容后n行 B before 内容前n行 C count? 内容前后n行 就像是这样: grep -rn --color Exception -A10 -B2 error.log diff diff命令用来比较两个文件是否的差异。当然,在ide中都提供了这个功能,diff只是命令行下的原始折衷。对了,diff和patch还是一些平台源码的打补丁方式,你要是不用,就pass吧。 压缩 为了减小传输文件的大小,一般都开启压缩。linux下常见的压缩文件有tar、bzip2、zip、rar等,7z这种用的相对较少。 .tar 使用tar命令压缩或解压 .bz2 使用bzip2命令操作 .gz 使用gzip命令操作 .zip 使用unzip命令解压 .rar 使用unrar命令解压 最常用的就是.tar.gz文件格式了。其实是经过了tar打包后,再使用gzip压缩。 创建压缩文件 tar cvfz archive.tar.gz dir/ 解压 tar xvfz. archive.tar.gz 日常运维 开机是按一下启动按钮,关机总不至于是长按启动按钮吧。对了,是shutdown命令,不过一般也没权限-.-!。passwd命令可以用来修改密码,这个权限还是可以有的。 mount mount命令可以挂在一些外接设备,比如u盘,比如iso,比如刚申请的ssd。可以放心的看小电影了。 mount /dev/sdb1 /xiaodianying chown chown 用来改变文件的所属用户和所属组。 chmod 用来改变文件的访问权限。 这两个命令,都和linux的文件权限777有关。 示例: # 毁灭性的命令 chmod 000 -R / # 修改a目录的用户和组为 xjj chown -R xjj:xjj a # 给a.sh文件增加执行权限(这个太常用了) chmod a+x a.sh yum 假定你用的是centos,则包管理工具就是yum。如果你的系统没有wget命令,就可以使用如下命令进行安装。 yum install wget -y systemctl 当然,centos管理后台服务也有一些套路。service命令就是。systemctl兼容了service命令,我们看一下怎么重启mysql服务。 推荐用下面这个。 service mysql restart systemctl restart mysqld 对于普通的进程,就要使用kill命令进行更加详细的控制了。kill命令有很多信号,如果你在用kill -9,你一定想要了解kill -15以及kill -3的区别和用途。 su su用来切换用户。比如你现在是root,想要用xjj用户做一些勾当,就可以使用su切换。 su xjj su - xjj -可以让你干净纯洁的降临另一个账号,不出意外,推荐。 系统状态概览 登陆一台linux机器,有些命令能够帮助你快速找到问题。这些命令涵盖内存、cpu、网络、io、磁盘等。 uname uname命令可以输出当前的内核信息,让你了解到用的是什么机器。 uname -a ps ps命令能够看到进程/线程状态。和top有些内容重叠,常用。 找到java进程 ps -ef|grep java top 系统状态一览,主要查看。cpu load负载、cpu占用率。使用内存或者cpu最高的一些进程。下面这个命令可以查看某个进程中的线程状态。 top -H -p pid free top也能看内存,但不友好,free是专门用来查看内存的。包括物理内存和虚拟内存swap。 df df命令用来查看系统中磁盘的使用量,用来查看磁盘是否已经到达上限。参数h可以以友好的方式进行展示。 df -h ifconfig 查看ip地址,不啰嗦,替代品是ip addr命令。 ping 至于网络通不通,可以使用ping来探测。(不包括那些禁ping的网站) netstat 虽然ss命令可以替代netstat了,但现实中netstat仍然用的更广泛一些。比如,查看当前的所有tcp连接。 netstat -ant 此命令,在找一些本地起了什么端口之类的问题上,作用很大。 工作常用 还有一些在工作中经常会用到的命令,它们的出现频率是非常高的 ,都是些熟面孔。 export 很多安装了jdk的同学找不到java命令,export就可以帮你办到它。export用来设定一些环境变量,env命令能看到当前系统中所有的环境变量。比如,下面设置的就是jdk的。 export PATH=$PATH:/home/xjj/jdk/bin 有时候,你想要知道所执行命令的具体路径。那么就可以使用whereis命令,我是假定了你装了多个版本的jdk。 crontab 这就是linux本地的job工具。不是分布式的,你要不是运维,就不要用了。比如,每10分钟提醒喝茶上厕所。 */10 * * * * /home/xjj/wc10min date date命令用来输出当前的系统时间,可以使用-s参数指定输出格式。但设置时间涉及到设置硬件,所以有另外一个命令叫做hwclock。 xargs xargs读取输入源,然后逐行处理。这个命令非常有用。举个栗子,删除目录中的所有class文件。 find . | grep .class$ | xargs rm -rvf #把所有的rmvb文件拷贝到目录 ls *.rmvb | xargs -n1 -i cp {} /mount/xiaodianying 网络 linux是一个多作业的网络操作系统,所以网络命令有很多很多。工作中,最常和这些打交道。 ssh 这个,就不啰嗦了。你一定希望了解ssh隧道是什么。你要是想要详细的输出过程,记得加参数-v。 scp scp用来进行文件传输。也可以用来传输目录。也有更高级的sftp命令。 scp a.txt 192.168.0.12:/tmp/a.txt scp -r a_dir 192.168.0.12:/tmp/ wget 你想要在服务器上安装jdk,不会先在本地下载下来,然后使用scp传到服务器上吧(有时候不得不这样)。wget命令可以让你直接使用命令行下载文件,并支持断点续传。 wget -c http://oracle.fuck/jdk2019.bin mysql mysql应用广泛,并不是每个人都有条件用上navicat的。你需要了解mysql的连接方式和基本的操作,在异常情况下才能游刃有余。 mysql -u root -p -h 192.168.1.2

问问小秘 2020-04-01 10:52:50 0 浏览量 回答数 0

回答

新地址 24题 Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。 23题 Spring Boot 的核心配置文件是application(.yml 或者 .properties) 和 bootstrap(.yml 或者 .properties) 配置文件。boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载,boostrap 里面的属性不能被覆盖。application 配置文件主要用于 Spring Boot 项目的自动化配置。bootstrap 配置文件的应用场景:使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;一些固定的不能被覆盖的属性;一些加密/解密的场景。 22题 优点:快速构建项目;对主流开发框架的无配置集成;starters自动依赖与版本控制;大量的自动配置,简化开发,也可修改默认值;无需配置XML,无代码生成,开箱即用;项目可独立运行,无须外部依赖Servlet容器;提供运行时的应用监控;与云计算的天然集成。缺点:集成度较高,使用过程中不太容易了解底层。 21题 Spring Boot的初衷就是为了简化spring的配置,使得开发中集成新功能时更快,简化或减少相关的配置文件。Spring Boot其实是一个整合很多可插拔的组件(框架),内嵌了使用工具(比如内嵌了Tomcat、Jetty等),方便开发人员快速搭建和开发的一个框架。 20题 当程序创建对象、数组等引用类型实体时,系统会在堆内存中为之分配一块内存区,对象就保存在内存区中,不需要显式的去释放一个对象的内存,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,标记那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。 19题 HashMap线程不安全,HashTable线程安全。HashMap允许有一个key为null,多个value为null;而HashTable不允许key和vale为null。继承类不一样,HashMap继承的是AbstractMap,HashTable继承的是Dictionary。初始容量不一样。使用的hashcode不一样。内部遍历方式的实现不一样。 18题 作用:内容可见性和禁止指令重排。内存可见性:某线程对 volatile 变量的修改,对其他线程都是可见的,即获取 volatile 变量的值都是最新的;禁止指令重排:重排序在单线程下一定能保证结果的正确性,但是在多线程环境下,可能发生重排序影响结果,若用volatile修饰共享变量,在编译时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。使用:当一个线程需要立刻读取到另外一个线程修改的变量值的时候,我们就可以使用volatile。区别:volatile是变量修饰符,而synchronized则作用于一段代码或者方法;volatile只是在线程内存和main memory(主内存)间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源;synchronized 关键字可以保证变量原子性和可见性,volatile 不能保证原子性。 17题 非公平主要表现在获取锁的行为上,并非是按照申请锁的时间前后给等待线程分配锁的 ,每当锁被释放后 ,任何一个线程都有机会竞争到锁,这样做的目的是为了提高执行性能 ,缺点是可能会产生线程饥饿现象 。 16题 如果线程遇到了 IO 阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。如果线程因为调用 wait()、sleep()、或者 join()方法而导致的阻塞,可以中断线程,并且通过抛出 InterruptedException 来唤醒它。 15题 原子操作就是无法被别的线程打断的操作。要么不执行,要么就执行成功。在Java中可以通过锁和循环CAS的方式来实现原子操作。从JDK 1.5开始提供了java.util.concurrent.atomic包,这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。 14题 wait()是Object类的方法,所以每一个对象能使用wait()方法。sleep()是Thread类中的静态方法。sleep不会释放锁,但会让出cpu,sleep会在指定的休眠时间后自动唤醒。wait则会释放锁,让出系统资源,并且加入wait set中,wait不会自动唤醒,而需要notify()或者notifyAll()唤醒。sleep和wait都可以被中断,使用sleep需要捕获异常。wait与notify、notifyAll只能在同步代码块中使用,而sleep可以在任何地方使用。 13题 Synchronized 是由 JVM 实现的一种实现互斥同步的一种方式,查看编译后的字节码,会发现被 Synchronized 修饰过的程序块,在编译前后被编译器生成了monitorenter 和 monitorexit 两个字节码指令。在虚拟机执行到 monitorenter 指令时,首先要尝试获取对象的锁:如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器+1;当执行 monitorexit 指令时将锁计数器-1;当计数器为0时,锁就被释放了。如果获取对象失败了,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。Java 中 Synchronize 通过在对象头设置标记,达到了获取锁和释放锁的目的。 12题 Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler 的 invoke()方法,只会拦截那些你指定需要拦截的方法。 实现方法:1.编写Intercepror接口的实现类;2.设置插件的签名,告诉mybatis拦截哪个对象的哪个方法;3.最后将插件注册到全局配置文件中。 11题 Mybatis可以映射枚举类,不单可以映射枚举类,Mybatis可以映射任何对象到表的一列上。映射方式为自定义一个TypeHandler,实现TypeHandler的setParameter()和getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType至jdbcType 的转换,二是完成jdbcType至javaType的转换,体现为 setParameter()和getResult()两个方法,分别代表设置sql问号占位符参数和获取列查询结果。 10题 Mybatis使用RowBounds对象进行分页,也可以直接编写sql实现分页,也可以使用Mybatis的分页插件。分页插件的原理:使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。举例:select * from student,拦截 sql 后重写为:select t.* from(select * from student)t limit 0,10。 9题 resultType和resultMap都是表示数据库表与pojo之间的映射规则的。类的名字和数据库相同时,可以直接设置resultType 参数为Pojo类。若不同或者有关联查询,需要设置resultMap将结果名字和Pojo名字进行转换。在项目中我们定义的resultMap多了property和column属性,实际也就是分别配置Pojo类的属性和对应的表字段之间的映射关系,多了这个映射关系以后,方便维护。 8题 之所以说Mybatis半自动化,是因为SQL语句需要用户自定义,SQL的解析、执行等工作由Mybatis执行。区别:Hibernate属于全自动 ORM 映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以它是半自动ORM映射工具。 7题 MyBatis 的缓存分为一级缓存和二级缓存。一级缓存是SqlSession级别的缓存,默认就有,在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据,不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。二级缓存是mapper级别的缓存,默认是不打开的,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。 6题 RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。用于方法上是为了细化映射,即根据特定的HTTP请求方法(GET、POST 方法等)、HTTP请求中是否携带特定参数等条件,将请求映射到匹配的方法上。 5题 1、前置通知(before advice):在目标方法调用之前执行; 2、后置通知(after returning advice):在目标方法调用之后执行,一旦目标方法产生异常不会执行; 3、最终通知(after(finally) advice):在目标调用方法之后执行,无论目标方法是否产生异常,都会执行; 4、异常通知(after throwing advice):在目标方法产生异常时执行; 5、环绕通知(around advice):在目标方法执行之前和执行之后都会执行,可以写一些非核心的业务逻辑,一般用来替代前置通知和后置通知。 4题 1、通过构造器或工厂方法创建Bean实例;2、为Bean的属性设置值和对其他Bean的引用;3、将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法;4、调用Bean的初始方法(init-method);5、将bean实例传递给bean后置处理器的postProcessAfterInitialization方法;6、bean可以使用了;7、当容器关闭时,调用Bean的销毁方法(destroy-method) 3题 在TransactionDefinition接口中定义了五个表示隔离级别的常量: ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。 ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 2 题 自动装配提供五种不同的模式供Spring容器用来自动装配beans之间的依赖注入: 1.默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean。 2.byName:通过参数名自动装配,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。 3.byType:按照参数的数据类型进行自动装配,之后容器试图匹配和装配和该bean的属性类型一样的bean。如果存在多个相同类型的bean对象,会出错。 4.constructor:使用构造方法完成对象注入,其实也是根据构造方法的参数类型进行对象查找,相当于采用byType的方式。 5.autodetect:如果找到默认的构造函数,则通过 constructor的方式自动装配,否则使用 byType的方式自动装配。在Spring3.0以后的版本此模式已被废弃,已经不再合法了。 1 题 循环依赖只会存在在单例实例中,多例循环依赖直接报错。Spring先用构造器实例化Bean对象,然后将实例化结束的对象放到一个Map中,并且Spring提供获取这个未设置属性的实例化对象的引用方法。当Spring实例化了A类、B类后,紧接着会去设置对象的属性,此时发现A类依赖B类,就会去Map中取出已经存在的单例B类对象,以此类推。因为所持有的都是引用,所以A类一改变B类也会跟着改变。从而解决循环依赖问题。

游客ih62co2qqq5ww 2020-03-03 18:05:36 0 浏览量 回答数 0

问题

Servlet 3.0 新特性详解? 400 报错

爱吃鱼的程序员 2020-06-04 11:52:09 3 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅