一定yaokan!!!
1.使用缓存的目的:
提高应用程序的性能,减少到数据库的访问次数
2.缓存的介质(缓存的存储位置)
内存:临时性存储空间 存取数据快 减少网络通信量
硬盘:永久性存储空间 存取速度慢
3.缓存的分类
客户端缓存:浏览器
服务器缓存:oscache,redis,memcache
4.缓存什么样的数据?
经常访问,又不经常修改的数据
5.缓存的有效性
为了避免脏数据的产生,要刷新缓存
6.脏数据
如果缓存中的数据和数据库中的数据不一致,那么缓存中的数据就被称之为脏数据
7.刷新缓存的方式
手动刷新:写程序的时候调用指定的代码清除缓存数据
定时刷新:当到达缓存过期时间后,会自动刷新数据
8.缓存的层次(一般我们将缓存加载service中)
jsp-->action-->service-->dao
缓存越靠前对性能的提高越大
9.缓存的清除策略:(缓存空间不足需要进行清理的时候使用)
LRU:最近最少使用原则.(理解:存储书)
FIFO:先进先出的缓存策略.(理解:排队)
10.什么时候使用缓存的清除策略?
当缓存中的数据已满,又有新的数据进来时,执行缓存的清除策略
Maven两个重点:根据Maven的约定由于配置了四个文件的文件名必须是固定的,还有一个loge日志的名字也是固定的,这样不需要去加载这些文件直接通过Maven的约定由于配置自动加载好
还有根据maven的依赖管理在pom.xml中配置jar与这个jar包相关的jar包自动配置好
我当时是怎么配置maven的通过在服务端中setting 中配置这个mirror镜像配置访问nexus的访问路径
这样我们就可以通过pom.xml先到我们的本地去找,如果本地仓库找不到在去maven私服去找如果私服找不到在去外网下载使用maven这样可以提高我们的开发效率与节省了下载带宽,以及jar包的重用性。
@Controller:使其普通的java类充当控制层的作用。
@RequestMapping:有两个参数 url 代表要访问的路径 method请求方式
@Service::使其java类充当service层。
@Repository::使其java类充当持久层。
@Resource:默认按照名字注入指定的bean。
@Autowired:默认按照类型进行注入可以结合@Qualifier("bean的的名字 名字")使使其按照名字进行注入。他是 其按照名字进行注入。他是Spring中的注解。
@RespsonceBody:将controller的方法返回的对象通过适当的转换器转换为指定个时候将其输出(通常适用于返回json/xml)
@RequestParam
作用:1.在文件上传时注解 @requestParam 后跟multilpartFile属性
2.接收指定参数名的参数并对方法中的参数赋值并且可以设置默认值
我们通常使用Spring MVC来充当我们项目中的控制层,我们控制层的作用就是接受前台传递的参数,调用业务逻辑层进行业务处理以及将返回的结果集返回前台进行展示,首先我们要在web.xml中配置Spring MVC的前端总控制器DispatcherServlet并加载Spring MVC的配置文件,我们在Controller层上加上@Controller注解,使其充当控制层,并且要在Spring mvc的配置文件中通过component-scan对Controller层进行扫描从而使类中的@Controller注解生效,Spring mvc用方法来接收参数,所以我们说Spring mvc是基于方法的设计,我们也可以通过@PathVariable从路径中获取信息,我们通常通过@Resource这个注解来进行Bean注入,他是java中的注解,而不是Spring中的,默认是按照属性名进行注入,我们也可以通过设置name属性的值,让其只能按照属性名进行注入,我们也可以用@Autowired注解来进行Bean的注入,他默认是按照类型进行注入,如果要按属性名进行注入我们需要结合@Qualifier注解使其按照名字进行注入,我们可以将返回值的类型改为ModelAndView并在配置文件中配置视图解析器的前缀和后缀,以此来给我们前台页面传递数据,也可以在方法中通过ModelMap进行返回数据。也可以通过@ResponseBody将返回的实体类或者实体类的集合转换为指定的格式进行前台页面交互。并且要在配置文件中进行相关的配置。@RequestMapping是将Url映射到具体的方法上。文件上传时我们通过@RequestParam来接收前台上传的文件。以上就是我对Spring MVC的理解和运用。
SSH整合的流程
在项目中首先是通过在web.xml中配置strtus2的前端控制器filterDispatcher加载struts.xml
配置文件并对指定的后缀名进行拦截,并且通过配置spring的监听器contextLoadListener
加载spring的相关配置文件如
spring-service.xml,spring-dao.xml,spring-common.xml,
之后新建控制层的类继承于BaseAction,而BaseAction继承于ActionSupport,
在BaseAction中封装了常用的方法如getRealPath(),outJson()等,
之后控制层注入service层,service层注入dao,dao层继承于HibernateDaoSupport
并注入spring-common.xml中配置的sessionFactory,sessionFactory注入dataSource连接数据库,
注入hibernate.cfg.xml从而加载hbm.xml文件,
除此之外还通过Spring中的Aop配置了事务并且通过切点表达式对Servcie层代码进行控制。
======================================================================SSM整合的流程
在项目中通过在web.xml配置springMVC的核心控制器DispatcherServlet
并加载Spring-mvc-controller.xml,并且通过配置Spring的监听器contextLoaderListener
加载spring-common.xml,之后新建控制层并在类上加入@Controller和@RequestMapping注解,
并通过@Resouce注入service层,在
service的实现类上加入@Service注解并通过@Autowired注入dao层,
dao层只有接口并没有实现类,
是通过在mybatis中对应的含有sql语句的xml文件中来通过namespace指明要实现的dao层的接口,
并使sql语句的id和dao层接口中的方法名一致从而明确调用指定dao层接口时要执行的sql语句。
并且在spring-mvc-controller.xml中配置了component-scan对controller
进行扫描从而使控制层的注解生效还配置了内部视图解析器从而在控制层进行页面跳转时加上指定的前缀和后缀,
在spring-common.xml中配置了dbcp数据库连接池以及sqlSession来加载mapper下所有的xml
并对所有的mapper层进行扫描也就是对dao层的扫描,
还通过Aop中的切点表达式对service层进行事务控制,并且对service层进行扫描使其注解生效。
Spring 是完全面向接口的设计,降低程序耦合性,主要是事务控制并创建bean实例对象。在ssh整合时,充当黏合剂的作用。IOC(Inversion of Control) 控制反转/依赖注入,又称DI(Dependency Injection) (依赖注入)
IOC的作用:产生对象实例,所以它是基于工厂设计模式的
Spring IOC的注入
通过属性进行注入,通过构造函数进行注入,
注入对象数组 注入List集合
注入Map集合 注入Properties类型
Spring IOC 自动绑定模式:
可以设置autowire按以下方式进行绑定
按byType只要类型一致会自动寻找,
按byName自动按属性名称进行自动查找匹配.
AOP 面向方面(切面)编程
AOP是OOP的延续,是Aspect Oriented Programming的缩写,
意思是面向方面(切面)编程。
注:OOP(Object-Oriented Programming ) 面向对象编程
AOP 主要应用于日志记录,性能统计,安全控制,事务处理(项目中使用的)等方面。
Spring中实现AOP技术:
在Spring中可以通过代理模式来实现AOP
代理模式分为
静态代理:一个接口,分别有一个真实实现和一个代理实现。
动态代理:通过代理类的代理,接口和实现类之间可以不直接发生联系,而 可以在运行期(Runtime)实现动态关联。
动态代理有两种实现方式,可以通过jdk的动态代理实现也可以通过cglib
来实现而AOP默认是通过jdk的动态代理来实现的。jdk的动态代理必须要有
接口的支持,而cglib不需要,它是基于类的。
Spring AOP事务的描述:
在spring-common.xml里通过
Spring实现ioc控制反转描述:
原来需要我们自己进行bean的创建以及注入,而现在交给
spring容器去完成bean的创建以及注入。
所谓的“控制反转”就是 对象控制权的转移,
从程序代码本身转移到了外部容器。
官方解释:
控制反转即IoC (Inversion of Control),
它把传统上由程序代码直接操控的对象的调用权交给容器,
通过容器来实现对象组件的装配和管理。
所谓的“控制反转”概念就是对组件对象控制权的转移,
从程序代码本身转移到了外部容器。
1.Map是一个以键值对存储的接口。Map下有两个具体的实现,分别是HashMap和HashTable.
2.HashMap是线程非安全的,HashTable是线程安全的,所以HashMap的效率高于HashTable.
3.HashMap允许键或值为空,而HashTable不允许键或值为空.
HashMap底层就是一个数组结构,数组中的每一项又是一个链表。
当新建一个HashMap的时候,就会初始化一个数组。
Entry就是数组中的元素,每个 Entry 其实就是一个key-value对,
它持有一个指向下一个元素的引用,这就构成了链表。
HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。
HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,
当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,
再根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,
也会根据hash算法找到其在数组中的存储位置,
再根据equals方法从该位置上的链表中取出该Entry。
Jdk【Java Development ToolKit】就是java开发工具箱, JDK是整个JAVA的核心里边包含了jre,它除了包含jre之外还包含了一些javac的工具类,把java源文件编译成class文件,java文件是用来运行这个程序的,除此之外,里边还包含了java源生的API,java.lang.integer在rt的jar包里边【可以在项目中看到】,通过rt这个jar包来调用我们的这些io流写入写出等
JDK有以下三种版本:
J2SE,standard edition,标准版,是我们通常用的一个版本
J2EE,enterpsise edtion,企业版,使用这种JDK开发J2EE应用程序
J2ME,micro edtion,主要用于移动设备、嵌入式设备上的java应用程序
Jre【Java Runtime Enviromental】是java运行时环境,那么所谓的java运行时环境,就是为了保证java程序能够运行时,所必备的一基础环境,也就是它只是保证java程序运行的,不能用来开发,而jdk才是用来开发的,所有的Java程序都要在JRE下才能运行。
包括JVM和JAVA核心类库和支持文件。与JDK相比,它不包含开发工具——编译器、调试器和其它工具。
Jre里边包含jvm
Jvm:【Java Virtual Mechinal】因为jre是java运行时环境,java运行靠什么运行,而底层就是依赖于jvm,即java虚拟机,java虚拟机用来加载类文件,java中之所以有跨平台的作用,就是因为我们的jvm
关系:
J2se是基于jdk和jre,
JDK是整个JAVA的核心里边包含了jre,
Jre里边包含jvm
1.List和Set都是接口,他们都继承于接口Collection,List是一个有序的可重复的集合,而Set的无序的不可重复的集合。Collection是集合的顶层接口,Collections是一个封装了众多关于集合操作的静态方法的工具类,因为构造方法是私有的,所以不能实例化。
2.List接口实现类有ArrayList,LinkedList,Vector。ArrayList和Vector是基于数组实现的,所以查询的时候速度快,而在进行增加和删除的时候速度较慢LinkedList是基于链式存储结构,所以在进行查询的时候速度较慢但在进行增加和删除的时候速度较快。又因为Vector是线程安全的,所以他和ArrayList相比而言,查询效率要低。
我负责项目中的系统管理模块,其中包含用户管理,菜单管理以及给用户赋角色,给角色赋权限;涉及到的表有用户表,角色表,用户角色关联表,菜单表,角色菜单关联表。在菜单管理模块采用ztree进行菜单的增删改查操作,为了将权限控制到按钮级别我们在进行菜单管理时会设置该菜单是属于按钮级别还是普通菜单,通过在数据库中增加一个type类型的字段来实现,如type为1则是普通菜单,type为2则是按钮菜单。
这样用户在登录的时候根据用户名和密码到用户表验证信息是否合法,如果合法则获取用户信息,之后根据用户id再到用户角色关联表中得到相关联的角色id集合,之后根据角色id集合再到角色权限关联表中获取该角色所拥有的权限id集合,然后再根据权限id集合到权限表(菜单表)中获取具体的菜单,展现给当前登录用户,从而达到不同用户看到不同的菜单权限。
为了防止用户不登录而直接访问后台资源我通过在项目中加入LoginInterceptor拦截器对未经认证的用户进行拦截,如果未经认证则跳转到登录页面使用户再次登录,除此之外还加入了PermissionInterceptor拦截器来对用户无权访问的资源进行拦截,如果无访问权限则跳转到没有访问权限的页面。
再者考虑到性能将用户登录后所拥有的资源权限通过OScache结合单例设计模式将数据存储到了缓存中,这样可以避免每次操作都需要重新进行查询的代价,减少和数据库的交互次数,提高系统性能。考虑到单例的设计模式在多线程中会出现线程安全的问题,所以就给单例加了双重判断锁,从而避免该问题的发生。
共同点:
不同点
1.get是从服务器上获取数据,post是向服务器传送数据,
2.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。
3.get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
4.在进行文件上传时只能使用post而不能是get。
5.不明确是post请求的都是get请求
1、从数据共享上
Forword是一个请求的延续,可以共享request的数据
Redirect开启一个新的请求,不可以共享request的数据
2、从地址栏
Forword转发地址栏不发生变化
Redirect转发地址栏发生变化
HTTP是一个超文本传输协议,属于OSI七层模型的应用层,由请求和响应构成,
是一个标准的客户端服务器模型。HTTP是无状态的也就是说同一个客户端的这次请求和上次请求是没有对应关系。
http的工作流程:
当发送一个http请求时,首先客户机和服务器会建立连接,
之后发送请求到服务器,请求中包含了要访问的url地址,请求的方式(get/post),
以及要传递的参数和头信息,服务器接到请求后会进行响应,
包括状态行,状态码,响应头,以及要响应的主体内容。客户端接收
到请求后将其展示到浏览器上然后断开和服务器端的连接。
简单说就是:建立连接--》发送请求--》响应--》断开连接
在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,
但任务结束就中断连接。
从 HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,
如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。
实现长连接要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
jquery是一个轻量级的js框架,具有跨浏览器的特性,兼容性好,
并且封装了很多工具,方便使用。
常用的有: 选择器 ,dom操作 ,ajax(ajax不能跨域) ,特效,工具类
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。
判断事务是否配置成功的关键点在于出现异常时事务是否会回滚
事务的ACID属性
1. 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,
要么都不发生。
2. 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
3. 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰.
4. 持久性(Durability)
持久性是指一个事务一旦被提交,
它对数据库中数据的改变就是永久性的.即使系统重启也不会丢失.
在JDBC中,
事务默认是自动提交的,
每次执行一个 SQL 语句时,如果执行成功,
就会向数据库自动提交,而不能回滚
为了让多个 SQL 语句作为一个事务执行:
(1)执行语句前调用 Connection 对象的 setAutoCommit(false);
以取消自动提交事务
(2)在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
(3)在出现异常时,调用 rollback(); 方法回滚事务。
1、索引的概念
索引就是为了提高数据的检索速度。
数据库的索引类似于书籍的索引。
在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息。
在数据库中,索引也允许数据库程序迅速地找到表中的数据,
而不必扫描整个数据库.
2、索引的优点
1.创建唯一性索引,保证数据库表中每一行数据的唯一性
2.大大加快数据的检索速度,这也是创建索引的最主要的原因
3.减少磁盘IO(向字典一样可以直接定位)
3、索引的缺点
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
2.索引需要占用额外的物理空间
3.当对表中的数据进行增加、删除和修改的时候,
索引也要动态的维护,降低了数据的维护速度
4、索引的分类
1.普通索引和唯一性索引
普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)
唯一性索引:保证在索引列中的全部数据是唯一的
CREATE unique INDEX mycolumn_index ON mytable (myclumn)
2. 单个索引和复合索引
单个索引:对单个字段建立索引
复合索引:又叫组合索引,在索引建立语句中同时包含多个字段名,
最多16个字段
CREATE INDEX name_index ON userInfo(firstname,lastname)
3.顺序索引,散列索引,位图索引
首先不考虑查询条件 先写分页语句 在写条件
1.例如:河北省不满18周岁的男的4,5,6条信息
select * from
(select t.* ,rownum rn from
(select id,name, age,sex from t_student where name="河北" and age<18 and sex="男") t
where rownum <= 6)
where rn >=4
2.女生年龄从高到低排序 每页3条 查询第3条
select * from
(select t.*,rownum rn from
(select id,name,age from t_student order by age desc) t
where rownum <= 9)
where rn>=7
第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。
第二范式(2NF): 首先是满足第一范式,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不是部分依赖。
第三范式(3NF): 首先满足第二范式,非主键列直接依赖于主键,消除传递依赖。
rowid物理位置的唯一标识。
而id是逻辑上的唯一标识,所以rowid查找速度要快于id,是目前最快的
定位一条记录的方式
rowid和rownum都是"伪数列"
所谓“伪数列”也就是默认隐藏的一个数列。
rownum用于标记结果集中结果顺序的一个字段,
它的特点是按顺序标记,而且是连续的,
换句话说就是只有有rownum=1的记录,才可能有rownum=2的记录。
rownum关键字只能和<或者<=直接关联
如果是>或者=则需要给他0起个别名
单例就是该类只能返回一个实例(实例只会创建一次)
单例所具备的特点:
1.私有的构造函数
2.私有的静态的全局变量
3.公共的静态的方法
双重锁定式
public class Singleton {
private Singleton(){};
private static Singleton single;
public static Singleton getInstance(){
if(null ==single){
Synchronized(single){
if(null == single){
single = new Singleton();
}
}
}
return single;
}
}
在创建主键的同时会生成对应的唯一索引,主键在保证数据唯一性的同时不允许为 空,而唯一可以有一个为空数据项,一个表中只能有一个主键,但是一个主键可以 有多个字段,一个表中可以有多个唯一索引。
数据库连接池的优点运行原理:
在我们不使用数据库连接池的时候,每次访问数据库都需要创建连接,
使用完成之后需要释放关闭连接,而这样是很耗费资源的。当我们使用
数据库连接池的时候,在tomcat启动的时候就创建了指定数量的连接,
之后当我们程序使用的时候就直接从连接池里面取,而不需要创建,同理,
当我们使用完的时候也不需要关闭连接,而是将连接返回到连接池中,供
其他请求继续使用。
DBCP:比较稳定。
C3P0: 性能比较高。
Hibernate属于全自动, Ibatis属于半自动,Jdbc属于手动,从开发效率上讲hibernate较高,ibatis居中,jdbc较低,从执行效率上讲hibernate较低,ibatis居中,jdbc较高,因为jdbc是手工写sql语句,程序员对sql的控制能力更大,可以根据业务需要进行优化,而ibatis虽然也可以对sql进行优化,但是他里面将resultset封装为实体的过程中采用了反射机制所以一定程度上影响了性能,而hibernate因为高度封装所以开发效率相对较高,但正因为这个原因,所以程序员在对sql语句的控制和优化方面相对比较弱,而且在将resultset封装成实体的过程中也采用了反射机制,所以在性能方面较低
外键必须加索引。
避免在 where 子句中对有索引的字段进行运算,这会导致索引失效,从而进行全表扫描。
在 where 及 order by 涉及的列上建立索引,要尽量避免全表扫描。
在设计表时要避免表中字段出现null的情况,通常要为其设置默认值。
避免在查找时放弃使用索引而进行全表扫描。
SELECT语句中避免使用'*’,只查询需要返回的字段 ,这样可以减少oracle解析sql语句的时间。
用NOT EXISTS 替换 NOT IN 操作符,用 EXISTS 替换 IN
解析大文件的xml数据使用sax替代dom4j,使用分段批量提交来完成大数据量的插入。
对于大批量字符串的拼接使用stringbuffer或者stringbuilder代替string进行+拼接。
根据业务情况使用缓存减少对数据库的访问。
单线程应尽量使用 HashMap, ArrayList,因为HashTable,Vector使用了同步机制,降低了性能。
在finally块中关闭流,断开连接,释放资源。
避免在循环条件中使用复杂表达式 。
3.Hibernate优化:
在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中,这缓存大太时会严重显示性能,所以在使用Hibernate处理大数 据量的,可以使用session. clear()或者session. evict(Object) ,在处理过程中,清除全部的缓存或者清除某个对象。
通过使用Hibernate的一级缓存,二级缓存,查询缓存等来提高性能 (必须)
Hibernate可以通过设置hibernate.jdbc.fetch_size,hibernate.jdbc.batch_size等属性,对Hibernate进行优化。
Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,Batch Size越大和数据库交互的次数就越少,速度就越快, 但也不要无限的大下去,通常选择一个合适的值,如100条;其次我们在进行大批量数据的导入操作时,可以结合batchsize进行分段批量提交,从而达到最优效果。
29.数据库优化?(被动说)
数据库优化:作为开发人员最主要是从sql语句的优化方面考虑的,对于数据库底层的优化,是由DBA完成的。
在我们公司里面做项目的时候,在开发过程中最主要是由程序员对java代码以及sql语句这方面进行优化,至于数据库 底层的优化,则由DBA在项目基本结尾进行压力测试的时候参与进来,通过对数据库的分析,确定影响性能的sql语句以及相关的表,通过和我们进行交流然后对其进行适当的改进。
慢日志就是在我们设置的时间内执行慢的语句可以在慢日志看到!
2.分表:
时间划分 地区划分
水平划分 垂直划分(把平常经常使用的提取出来加上索引)
3.在mysql中通过explain查看执行计划
在做XX电商项目的时候,考虑到提高网站前台的性能,承受更大的并发,我们将网站首页和很多文章页面都进行了静态化。当时采用的方式是通过freemarker模板引擎和spring定时器来结合完成的。前台美工通过网站管理后台用freemarker编写首页模板以及相关的样式,之后将模板信息存入模板表,我负责编写spring定时器在每晚的凌晨从数据库中的模板表中取出各种类型的模板并和相关的数据结合起来生成静态的html页面。并且考虑到减少前台美工编写freemarker标签的难度,我将经常用到的一些功能像分页,列表展示等通过#macro编写为freemarker的宏命令,方便前台美工直接使用。对于及时性要求比较高的特别热门的频道,则在用户点击发布时直接调用编写的接口通过freemarker和数据结合生成html静态页面。
redis是一个基于key,value的支持多种数据类型(String,List,Set,zSet,Hash)的可进行持久化的内存数据库。我们在项目中通常使用redis来充当缓存服务器来缓存分类列表,品牌列表,热销商品,推荐商品以及该商品的关联商品等等。以前做项目的时候,我们是把商品的信息存放在redis里面,redis支持多种数据类型,有两种方法存储对象:1,可以把对象序列化进行存储,然后反序列化取出。2.用hash结构存储,最后发现,还是用hash存取比较快
当时我们就是在redis中设置maxmemory【最大内存】,把maxmemory-policy【数据清除策略】设置为allkeys-lru。为了保证redis不会因为占用内存过大而导致系统宕机,也会设置最大内存和数据清除策略。使用了jedis作为客户端,并考虑到性能问题使用了jedis连接池。考虑到redis服务器的高可用性,我们做了redis的主从复制,刚开始配置redis的时候,我是关闭它的保护模式,虽然实现了功能,但是不安全,最后是在redis.conf配置文件中绑定具体的ip地址,这样只有该ip地址才能访问redis服务器,并且设置长度为20位左右的密码,从而保证只有进行了密码授权才能进行相关的操作,为了信息安全,我们配置了redis的主从复制,在从服务器的配置文件中通过配置slaveof绑定主服务器的ip地址和端口号,
当设置好slave服务器后,slave会建立和master的连接,然后发送sync命令。无论是第一次同步建立的连接还是连接断开后的重新连接,master都会启动一个后台进程,将数据库
快照保存到文件中,同时master主进程会开始收集新的写命令并缓存起来。后台进程完成写文件后master就发送文件给slave,slave将文件保存到磁盘上,然后加载到内存恢复数据库快照到slave上。接着master就会把缓存的命令转发给slave。而且后续master收到的写命令都会通过开始建立的连接发送给slave。从master到slave的同步数据的命令和从 client发送的命令使用相同的协议格式。当master和slave的连接断开时slave可以自动重新建立连接。如果master同时收到多个slave发来的同步连接命令,只会使用启动一个进程来写数据库镜像,然后发送给所有slave。
哨兵要监视 Redis 服务器,就必须连接 Redis 服务器。启动哨兵的时候需要指定一个配置文件,程序初始化的时候会读取这个配置文件,获取被监视 Redis 服务器的 IP 地址和端口等信息。
哨兵连接redis服务器发送两个连接一个是普通连接,另一个是订阅发布专用连接。哨兵在初始化订阅发布连接的时候,做了两个工作:一是,向 Redis 服务器发送 SUBSCRIBE SENTINEL_HELLO_CHANNEL命令;二是,注册了回调函数 sentinelReceiveHelloMessages()。
哨兵会向 hello 频道发送包括:哨兵自己的IP 地址和端口,runid,当前的配置版本;其所监视主机的 IP 地址,端口,当前的配置版本。【这里要说清楚,什么是 runid 和配置版本】虽然未知的信息很多,但我们可以得知,当一个哨兵新加入到一个 Redis 集群中时,就能通过 hello 频道,发现其他更多的哨兵,而它自己也能够被其他的哨兵发现,哨兵向与 Redis 服务器的命令连接通道上,发送了一个INFO 命令(字符串);并注册了回调函数sentinelInfoReplyCallback()。Redis 服务器需要对 INFO 命令作出相应,能在 redis.c 主文件中找到 INFO 命令的处理函数:当 Redis 服务器收到INFO命令时候,会向该哨兵回传数据,包括:
关于该 Redis 服务器的细节信息,rRedis 软件版本,与其所连接的客户端信息,内存占用情况,数据落地(持久化)情况,各种各样的状态,主从复制信息,所有从机的信息,CPU 使用情况,存储的键值对数量等。
由此得到最值得关注的信息,所有从机的信息都在这个时候曝光给了哨兵,哨兵由此就可以监视此从机了。
Redis 服务器收集了这些信息回传给了哨兵,刚才所说哨兵的回调函数 sentinelInfoReplyCallback()会被调用,它的主要工作就是着手监视未被监视的从机;完成一些故障修复(failover)的工作。连同上面的一节,就是Redis 的 auto discover 的全貌了。
在哨兵的定时程序中,哨兵会向所有的服务器,包括哨兵服务器,发送 PING 心跳,而哨兵收到来自 Redis 服务器的回应后,也会更新相应的时间点或者执行其他操作,哨兵不仅仅凭借自己的信息,还依据其他哨兵提供的信息判断 Redis 服务器是否下线的方法称为客观方法,即通过所有其他哨兵报告的主机在线状态来判定某主机是否下线。
一个 Redis 集群难免遇到主机宕机断电的时候,哨兵如果检测主机被大多数的哨兵判定为下线,就很可能会执行故障修复,重新选出一个主机。一般在 Redis 服务器集群中,只有主机同时肩负读请求和写请求的两个功能,而从机只负责读请求,从机的数据更新都是由之前所提到的主从复制上获取的。因此,当出现意外情况的时候,很有必要新选出一个新的主机。
优选选择优先级高的从机
优先选择主从复制偏移量高的从机,即从机从主机复制的数据越多
优先选择有 runid 的从机
如果上面条件都一样,那么将 runid 按字典顺序排序
并且通过加入哨兵来使redis主服务器宕机时,从服务器自动转换为主服务器继续提供服务。
①加载数据库驱动程序(Class.forName("数据库驱动类");)
②连接数据库(Connection con = DriverManager.getConnection();)
③操作数据库(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)
④关闭数据库,释放连接(con.close();)
悲观锁/乐观锁:
悲观锁(Pessimistic Lock), 每次去查询数据的时候都认为别人会修改,
所以每次在查询数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
传统的关系型数据库里边就用到了这种锁机制,比如通过select ....for update进行数据锁定。
乐观锁(Optimistic Lock), 每次去查询数据的时候都认为别人不会修改,
所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,
可以使用版本号,时间戳等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
spring中事务的传播特性好像有5个左右,
我做项目的时候使用最多的就是PROPAGATION_REQUIRED,
它所代表的意思支持当前事务,如果当前没有事务,就新建一个事务。
spring中事务的隔离级别有5个,默认使用的是ISOLATION_DEFAULT,
它代表使用数据库默认的事务隔离级别,也是我们项目中最常使用的。
除此之外还有
读未提交:
它充许另外一个事务可以看到这个事务未提交的数据,
这种隔离级别会产生脏读,不可重复读和幻像读。
读提交:
保证一个事务修改的数据提交后才能被另外一个事务读取,
也是大多数数据库的默认值。可以避免脏读,但会产生不可重复读和幻像读。
重复读:
在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
串行化:
顺序执行事务。除了防止脏读,不可重复读外,还避免了幻像读。
并发性也最低,但最安全。
不可重复读的重点是修改 :
同样的条件 , 你读取过的数据 , 再次读取出来发现值不一样了 。
幻读的重点在于新增或者删除 :
同样的条件 , 第 1 次和第 2 次读出来的记录数不一样。
mongodb是一个nosql数据库,我们在项目中通常用它来存储评论信息,
【评论id,商品id,标题,评分,内容,评论人信息,评论的发布时间】
因为每个商品都会有评论信息,而且某些热门商品的评论信息可能是数千条,
mongodb正好适用于这种大数据量、高并发、弱事务的互联网应用。考虑
到mongodb的高可用性我们搭建了3台mongodb数据库来实现副本集,这样
不仅可以达到故障自动转移的特性而且也可以通过读写分离提高性能,即便
主服务器宕机了,还会通过投票选举出下一个主服务器继续提供服务。
再者考虑到我们的项目最后要部署到多台tomcat通过nginx来实现负载均衡,
为了对项目中的文件以及图片进行统一的管理,我们就用mongodb来充当文件服务器。
对于大部分的单张图片和单个文件来说小于16M,所以我们就以常规的方式来将
文件转换为二进制的字节数组进行保存。考虑到高可用性以及为了应对后期随着文件数量的不断
增加而能够方便进行扩容,我们建立了3个分片并将分片和副本集做了整合,每个分片都是一个副本集,这样
不仅满足了大数据量的存储也避免了分片中单台机器导致的单点故障问题。考虑到可能要处理
大于16M的文件,所以又增加了支持大文件存储的gridfs,这样即便再大的文件也会被gridfs分解为多个
chunk进行存储。
我们在项目中通常用EasyUI来充当展示层,因为它是一个RIA富客户端框架,
自身提供了很多功能强大的插件,可以提高用户的体验度而且也有助于我们
开发人员直接使用,提高开发效率。我们在项目中使用到的EasyUI插件有Layout布局,
EasyUI的tree,Tab页面,datagrid,form表单,Dialog对话框,Messager提示信息还有
Accordion手风琴效果,progress进度条等。
EasyUI的tree的生成方式有两种,一种是通过一条sql语句查询所有的菜单信息,
然后在java中通过递归的方式将其拼装成符合指定json格式的数据,这种适用
于数据量比较小的情况,通过减少数据库的访问次数提高性能,另一种是通过
ajax异步加载的方式,每点击一下树节点就向后台发送一次请求,从而来获取
该节点下的子节点,这种适用于数据量比较大的情况。这时候如果采用取出全
部数据递归拼装的话就有可能出现内存溢出。
我们当时在项目中是通过Easyui的tree来生成菜单,考虑到菜单的
数据量也不是特别的大,所以就采用了第一种取出所有数据并递归将其
拼装成指定Json的方式来提高性能,再者考虑到每个用户的菜单信息并
不是经常改变,所以又结合oscache缓存以及带有双重判定锁的单例模式
将其缓存到内存中,从而再次提高了性能。
在点击树形菜单,动态添加tab页的时候一定要注意,为了避免每次点击
都添加一个新的tab页,我们的做法是当点击事件发生时,先判断当前
选中的菜单所对应的tab页是否已经存在,如果存在就将其激活选中,否则
再添加新的。多个tab页出现的另一个问题就是不同tab页间的数据可能不
同步,所以我们会在每个tab页上面都增加一个刷新按钮,可以通过点击
该按钮给该tab页所对应的iframe的src属性重新赋值,来起到刷新的作用。
datagrid也是我们在项目中经常使用到的,在使用datagrid时应该注意的是
在拼装好的json数据中,需要有total和rows这两个属性,其中total用来
指明数据的总条数,rows用来指明当前页的数据列表;在前台页面中要保证
columns中的field和rows中的属性名相对应,否则数据就展现不出来,而且
对于图片等制定格式数据的展示需要结合formatter对其进行格式化才能进行
正确的显示。最后就是在datagrid和form表单结合进行数据查询时调用的是
load方法,进行增删改后刷新datagrid调用的是reload方法。
Bootstrap是一个支持响应式的Css框架它提供了很多组件,
如导航条,面板,菜单,form表单,还有栅格,
而且他们这些都是支持响应式的,可以在各种
设备上进行完美的展现。这里面我感觉最有价值的就是
bootstrap提供的栅格系统,这个栅格系统将
整个页面分为12列,而且可以根据屏幕的宽窄进行自动
调节,这也是响应式的关键所在。在使用栅格系统的时候
要注意最外层样式是Container,里面是row,row里面包含
的是列,列里面可以用来填充各种各样的组件。
我在项目中使用bootstrap完成的情况大概是这个样子,
首先我使用了bootstrap的导航条,并将其固定在顶部,
使其在拖拉滚动条的时候不至于看不到,
之后在导航条的下面采用了bootstrap的栅格系统将其分为左右两部分,
左边使用bootstrap的Treeview组件,将菜单展现出来,当点击treeview
上的菜单节点时结合一个第三方的tab组件,将需要展示的内容放到tab页内,
并进行上下切分,上面使用了bootstrap的form组件,
下面使用了它的响应式表格以及分页组件,在进行增加修改时,
使用了第三方的bootbox弹出框。
基本来说MyISAM类型不支持事务处理而InnoDB类型支持。
MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,
但是不提供事务支持,而InnoDB提供事务支持以及外键。
MySQL主从复制 读写分离【主动】
我们在项目中的关系型数据库采用的是MySQL,考虑到对事务的支持使用的是InnoDB引擎,
为了保证数据库数据的安全,达到高可用性,以及分担服务器压力我们对MySQL进行了主从复制
的配置并结合MyCat这个数据库中间件进行读写分离。我们项目 目前采用的是一主带2或者3从的架构。
因为互联网项目一般都是读的多,写的少,所以通过这种一主多从的架构分担了单台数据库的压力
并且在一台服务器宕机的情况下也能保证项目的基本运行。
主从复制的配置步骤:【被动】
主从复制的配置比较简单,最主要是开启主服务器的二进制日志并指明一个唯一的
标识,从服务器也要指明一个唯一的标识,并且在主服务器上创建账号,开启复制权限;
在主服务器上运行show master status查看主服务器的状态,之后在从服务器上用刚才
建立的账号连接指定的的主服务器,并指明要复制的二进制文件以及起始位置,
最后运行start slave就可以了,然后通常运行show slave status查看从服务器的状态,
如果slave_io和slave_sql为yes,就证明配置成功了。
主从复制的运行原理:【被动】
最主要就是主服务器上的二进制日志以及从服务器上的IO线程,SQL线程,以及中继日志。
主服务器将其自身的改变存入到二进制日志中去,从服务器连接主服务器并通过IO线程读取
主服务器上的二进制日志,将读取的内容存入自身的中继日志,之后SQL线程会读取中继日志
中的sql语句对其进行执行,这样就保证了从服务和主服务器的一致性。MySQL的主从复制默认
是基于sql语句进行的。
北京市海定区阜外亮甲1号中关注联网创意产业园27号楼 (丰台区)
海淀区蓝靛厂 晨月园小区 远大路公交站上车 355/79/118线都能到 坐六站(定慧北桥下车)走大概5分钟就到了
公司附近 在那边有一个丰台科技原生态主题公园
晨月园附近有个巨人学校
从育新坐606路公交到成府路南口下车然后在步行到公司
15K 14K 13K 1000
郑州理工专修学院 计算机科学与技术 刘信古
有,还有,酒店服务管理 建筑工程 行政管理 轨道交通运营 等等。。。
计算机原理 计算机网络 高级语言 编程语言 操作系统 数据结构
26 马
合同到期,想换一个新的环境,公司这边也挽留我,但是在公司也呆了,2.3年了,
想换一个新的平台,来不断提升充实自己。
在上家公司的时候,人事说咱们公司的五险一金如果要上的话都是从自己工资里面扣的,
当时感觉没啥必要也就没上。
这几年做程序,因为要不断的对代码进行验证确认,所有感觉自己现在有点强迫症。
前2,3年继续加强自己的技术功底,然后朝着项目经理(技术经理,产品经理)方面发展
2008年9月 2012年6月 下了火车打个车10来块钱
(吹牛逼的活) 有一些卖衣服的 卖吃的 小超市 酒店什么的....
养老保险,医疗保险,失业保险,工伤保险,生育险 住房公积金
60人左右 技术部 销售部 行政部 人力资源部 财务部
ajax全称是异步JavaScript及xml;
ajax的核心JavaScript中的xmlHttpRequest(XHR);
使用ajax可以提高用户的体验度,进行异步数据传输从而提高性能。ajax不能跨域,所谓不能跨域就是不能跨多个网站(多个域名),不能跨多个项目可以通过jsonp来解决ajax跨域的问题,而jsonp的实质就是通过动态添加script标签来实现的
Ajax是默认没有超时时间,如果我们想要ajax超时在ajax中有一个timeout这个属性设置它的时间是根据秒来设置
Ajax 异步是跳转页面加载一部分数据当点击按钮的时候加载另一部分数据这样的使用于大数据量的加载
Ajax同步 是跳转页面一下子执行了说有的ajax请求加载了所有的数据这样的如果在大量数据中页面会卡
Ajax中有async属性 async =”true”是同步flase是异步 默认的是异步
原生的ajax是xmlhttprequest
(主动说)
webservice是SOA(面向服务编程)的一种实现,
主要是用来实现异构平台通信也就
是不同平台不同项目之间的数据传输,从而避免了信息孤岛的问题,
它之所以能够
进行异构平台通信是因为它是完全基于xml的,
所以说,webService是跨平台,
跨语言,跨框架的,在java中通常有三种技术框架分别是xfire,cxf,axis2。
我们为了保证
webservice的安全性,采用了基于
WS-Security标准的安全验证(使用回调函数)。
(没必要主动说)
webservice的三要素分别是:
wsdl(webservice description language)
用来描述发布的接口(服务)
soap(simple object access protocol)
是xml和http的结合,是webservice数据通信的协议
uddi 用来管理,查询webService的服务
(没必要主动说)
webservice的具体三种实现方式(框架)或者三种实现框架的区别
1. Axis2:可以用多种语言开发,
是一个重量级框架,功能非常强大,
但是它的性能比较低。
2. Xfire:它相比Axis2来说是一个轻量级框架,
它的性能要比Axis2高。
3. cxf:是Xfire的升级版,就好比是,
struts2是webwork的升级,
然后cxf和spring集成起来非常方便,简易,
性能方面也要比Xfire高。
【注】jdk6 自带的webservice jws
(主动说)
业务场景
我在以前做项目的时候,其中遇到一个功能,
需要进行两个项目之间的数据的传输,
项目经理让我去完成这个任务,我根据以往的项目经验,
想到两种解决方案,第一种
就是开放另外一个项目的数据库的权限给我,
然后我直接通过访问另外一个项目的数据
库,来得到需要的信息,但后来我分析了下,觉的这种方式不安全,
而且因为当时
这个项目是另外一家公司负责在做,所以数据库里面的表结构,
以及以后牵涉
到的责任问题都很多,所以我就采用了第二种方案,
即通过webservices的方式,进行
异构系统之间数据信息的传递,webservices的具体实现,
有xfire,cxf,axis2,
我根据以往的项目经验,了解到cxf是xfire的升级版本,适用于java语言,
xfire/cxf 性能比axis2要高,并且和spring整合起来也比较方便,
而axis2支持更多的语言,
性能相对于cxf要低,通过上面分析,
结合我们目前的两个项目都是基于java
语言的,所以我采用cxf这种方式实现了两个项目之间数据的传递,
我们为了保证
webservice的安全性我们采用了基于
WS-Security标准的安全验证(使用CXF回调函数)。
(没必要主动说)
webservice服务端配置流程
首先在web.xml中引入cxfServlet核心类,
指定对以/cxf开头的url路径提供webservice服务,
之后我们在要发布成webservice接口上添加@Webservice 注解,
而且还要在实现类上添加同样的webservice注解并且要说明实现了哪个接口,
之后在spring-webservice.xml中发布webservice服务,
通过jaxws:endpoint这个标签,
并且在标签配置implementor和address来表明实现服务的类,
以及发布的地址,
最后在浏览器中输入相关的webservice地址?wsdl来验证服务是否发布成功。
(没必要主动说)
webservice客户端的配置
首先通过wsdl2java根据发布的webservice服务端地址的wsdl
生成客户端调用的中间桥梁java类,
将生成的java类拷贝到客户端项目中,
配置spring-client.xml文件,
通过jaxws:client定义一个bean,
并通过address属性指明要访问的webservice的服务地址,
通过serviceClass指明充当中间桥梁的服务类,之后获取该bean,
就可以通过它来访问发布的webservice接口中的方法。
负载均衡:
(了解)
我们在做这个项目时,考虑到服务器性能的问题,最开始想到使用纵向扩展,来增加硬件的配置提高其性能,但这样做比较耗费资金,而且服务器内存空间也是有限的;所以后来就使用横向扩展来达到这一目的.
(主动说)
当时我们使用nginx(n g 个 s)+3个tomcat进行负载均衡,在我们不进行负载均衡之前,那所有的请求都由一台tomcat进行处理,这样会使我们的tomcat所承受的压力增大,而我们进行负载均衡之后,同样数量的请求经过nginx将其分发到多台tomcat进行处理,从而降低每台tomcat所承受的压力,而且当其中一台机器宕机时,其他机器还可以继续提供服务,保证服务不间断。
当时项目在部署完成后,遇到这么个问题,用户登录输入验证码的时候,明明验证码输入的正确,但总是提醒说验证码不正确从而不能正常登录,经过分析后发现有可能第一次
请求被发送到t1上,那么放在session中的验证码就被放到了t1上,当用户输入验证码点击登录时,新发送的请求有可能被发送到t2上面,这样在进行对比时就肯定会不一致从
而提示验证码输入错误,后来我就考虑使用ip_hash这种负载均衡策略来代替默认的轮询策略,虽然解决了验证码错误问题,但是在后续的测试中发现如果用户在使用过程中
突然一台服务器宕机了,那么因为session在这台服务器上存储着,所以就会提示用户重新登录,这样使用户的体验度非常不好,最后就通过将session信息保存到redis服务器中从而在
多台web服务器中实现session共享,这样就解决了上面所说的那些问题。
怎么避免nginx产生单点故障(被动说)
同时我们为了避免nginx的单点故障,达到高可用性,就在nginx的前面又加了一个F5,从而将请求分配给多个nginx,再通过nginx分配给多个不同的Tomcat。这样大大的提高了服务的有效性,并且进一步提高了性能。
1.Linux下常见的分支:
CentOS:服务端【纯开源】
RedHat:服务器端【收费】
Ubantu:个人电脑
2.访问方式:通过SSH/Putty客户端连接服务器
3.如何使用:
1.虚拟机的好处?
可以在虚拟机中随意操作系统,不怕影响或损害电脑;
2.克隆(备份):快速创建当前系统的备份,快速创建另外一个虚拟系统;
在manage 下的clone中
linked(链接克隆) 软克隆 优点:速度快,生成文件小;
full(完整克隆) 硬克隆 优点:文件大,速度比较慢;
选择桥接模式;
只查出四行 ping Ip -c 4
3.快照:可以将当前的虚拟系统快速还原到某一时刻;都是一个虚拟系统。
快照 Snapshot 下的 Take Snapshot
快照的好处:埋下几个点,方便还原
4.命令:
注意:
rpm是Linux下一种软件安转包的后缀名。如*。rpm ,等同于windows中的exe.rpm是一个命令,用来进行和软件安装相关的操作。(安转,卸载,查找)
linux下没有盘符的概念,它是通过相关的目录来管理资源的。我们通常在/home中创建文件夹来存放需要安转的软件
tab键自动补全 *代表当前目录下的所有文件
JDK默认安装在 usr/java中
设置jdk的环境变量:
修改/etc/profile文件
用文本编辑器打开 /etc/profile
在profile文件末尾加入:
export JAVA_HOME = /usr/java/jdk.1.7.0_79
export PATH = $JAVA_HOME/binL$PATH
source /etc/profile 使修改立即生效
echo $PATH 查看PATH值
1.ifconfig:查看IP地址
2.java -version :查jdk的版本
3.rpm -qa | grep 软件的名称 :查找和指定名称相关的软件
4.rpm -e --nodeps 软件的名称 :卸载指定的软件
5.rpm -ivh 软件名称 :安装指定的软件
6.uname -a 查看Linux系统的基本信息(计算机名,操作位数,版本号)
7.LL 查看文件夹下的文件
8.mkdir 创建文件夹
9.vi文件名: 对指定的文件名进行编译。
按i进入编辑模式,
按ESC键进入命令模式
:wq! 强制保存并退出
:q!强制退出(!是强制的意思)
10.pwd :查看当前目录的完整路径
11.unzip 文件名.zip :解压后缀名为zip的压缩文件
zip 文件名.zip 要压缩的文件
12.mv 源文件 目标文件名(mv可以移动/重命名)
13.rm -rf 文件夹名 :递归强制删除文件夹及其下的文件
14.service iptables stop 禁用防火墙
15.chmod +x *.sh :使所有的后缀名为sh的文件,拥有可执行的权限
16.在bin目录下 ./startup.sh 启动tomcat
17.在bin目录下通过tail -f ../logs/catalina.out 来查看启动日志 tail -n 300 ../logs/catalina.out 查看最后三百行的信息
18.cat 文件名:查看整个文件内容
19. ps -ef | grep 进程名:查看指定进程是否启动
20.kill -9 进程号 :强制杀死进程
killall -9 进程名
21. find / -name 文件名 -print :查看指定文件的路径
vi 在命令模式下 yy复制当前光标所在行
p粘贴
dd 删除当前行
vi /etc/sysconfig/iptables 更改防火墙的配置文件,开放新的端口号
重启防火墙 service iptables restart
查看当前防火墙的状态 service iptables status
export JAVA_HOME = /usr/java/jdk.1.7.0_79
export PATH = $JAVA_HOME/binL$PATH
source /etc/profile 使修改立即生效
echo $PATH 查看PATH值
我们在项目中的关系型数据库采用的是MySQL,考虑到对事务的支持使用的是InnoDB引擎,为了保证数据库数据的安全,达到高可用性,以及分担服务器压力我们对MySQL进行了主从复制的配置并结合MyCat这个数据库中间件进行读写分离。我们项目 目前采用的是一主带2或者3从的架构。因为互联网项目一般都是读的多,写的少,所以通过这种一主多从的架构分担了单台数据库的压力并且在一台服务器宕机的情况下也能保证项目的基本运行。
主从复制的配置比较简单,最主要是开启主服务器的二进制日志并指明一个唯一的标识,从服务器也要指明一个唯一的标识,并且在主服务器上创建账号,开启复制权限;在主服务器上运行show master status查看主服务器的状态,之后在从服务器上用刚才建立的账号连接指定的的主服务器,并指明要复制的二进制文件以及起始位置,最后运行start slave就可以了,然后通常运行show slave status查看从服务器的状态,如果slave_io和slave_sql为yes,就证明配置成功了。
最主要就是主服务器上的二进制日志以及从服务器上的IO线程,SQL线程,以及中继日志。主服务器将其自身的改变存入到二进制日志中去,从服务器连接主服务器并通过IO线程读取主服务器上的二进制日志,将读取的内容存入自身的中继日志,之后SQL线程会读取中继日志中的sql语句对其进行执行,这样就保证了从服务和主服务器的一致性。MySQL的主从复制默认是基于sql语句进行的。
60.MyCat概述?
1.需求分析
2.概要设计
3.详细设计(用例图,流程图,类图)
4.数据库设计(powerdesigner)
5.代码开发(编写)
6.单元测试(junit 白盒测试)(开发人员)
svn版本管理工具(提交,更新代码,文档)
7.集成测试 (黑盒测试,loadrunner(编写测试脚本)(高级测试))
8.上线试运行 (用户自己体验)
9.压力测试(loadrunner)
10.正式上线
11.维护
62.httpClient
httpClient是一个支持http协议的客户端编程工具包,我们在java中调用httpClient是通过url模拟了一个http请求,这样就可以通过java代码直接发送请求获得服务端响应数据,首先构建HttpClient,new DefaultHttpClient(); httpClient发送请求的方式也分成两种形式:一个 new httpGet(),一个是new httpPost() 把请求的url放进去,然后用excute发送请求,获取响应信息,里面包含状态码,成功为200,包含响应内容,将内容转换为字符串,最后关闭连接,其中post请求是模拟表单提交完成的、不能传递参数
63.多线程
1.java中实现线程的方式
在java中实现线程有两种方式:继承Thread类,实现Runable接口,一个java main程序默认会开启两个线程一个是主线程,一个垃圾回收线程。
2.线程不安全与安全:
多个线程访问同一个资源,导致结果和期望值不同,我们就说它是 非线程安全的(线程不安全),反之我们就说它是 线程安全的。
了解:
a.多个线程访问同一个资源(这里的资源通常指的是全局变量或者静态变量),如果每次运行结果和单线程运行的结果是一样的,就是线程安
全的。
b.线程安全问题都是由全局变量及静态变量引起的。
c.若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;
若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
3.线程的状态
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
了解:
1、线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但不管怎样,当我们new了这个对象后,线程就进入了初始
状态;
2、当该对象调用了start()方法,就进入可运行状态;
3、进入可运行状态后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态;
4、进入运行状态后情况就比较复杂了
4.1、run()方法或main()方法结束后,线程就进入终止状态;
4.2、当线程调用了自身的sleep()方法或其他线程的join()方法,就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资
源)。当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配时间片;
4.3、线程调用了yield()方法,意思是放弃当前获得的CPU时间片,回到可运行状态,这时与其他进程处于同等竞争状态,OS有可能会接
着又让这个进程进入运行状态;
4.4、当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchronized(同步),获取不到锁标记,将会立即进入锁
池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获
得锁标记后,就转入可运行状态,等待OS分配CPU时间片;
4.5、当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自
动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的
是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后
会进入锁池,等待获取锁标记。
补充:(wait和sleep的区别)
wait时会释放锁资源但sleep不会释放锁资源,wait通常和notify以及notifyAll结合使用,需要notify或者notifyAll对其进行唤醒,sleep通常在指定的时间内自动唤醒。
4.解决线程安全的问题的方案:
a.通过加锁(synchronized)的方式解决线程安全问题
1.synchronized 方法
2.synchronized 块(同步代码块)
b.避免使用全局变量
c.使用ThreadLocal(参考:http://blog.csdn.net/drifterj/article/details/7782706)
1. 为多线程并发的互斥控制提供了另一种全新的解决思路
2. 通过ThreadLocal为其他模块的API传递参数
5.java线程池 (可参考:http://www.oschina.net/question/565065_86540)
1.减少了创建和销毁线程的次数,
每个线程都可以被重复利用,
可执行多个任务。
2.可以根据系统的承受能力,
调整线程池中线程的数目,
防止因为消耗过多的内存,
而导致服务器宕机
(每个线程需要大约1MB内存,线程开的越多,
消耗的内存也就越大,最后宕机)。
通常我们使用的线程池是实现了ExecutorService的ThreadPoolExecutor。
6.死锁
死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程
中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等
待,而无法执行的情况。
死锁产生的原因:是由访问共享资源顺序不当所造成的.
简单的说:所谓死锁,是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
7.守护线程
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM
一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon
Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。
1.AOP是OOP(面向对象编程)的延续,是Aspect Oriented Programming的缩写,意思是面向方面编程或者面向切面编程。AOP是基于代理模式来实现的。(23种设计模式:工厂模式、代理模式、单例模式、适配器模式、责任链模式、装饰模式,模式的应用场景不是很明确,什么场景用什么模式都是可以理解或解释的。一个项目并不是运用的模式越多,则代表项目更强大,反而显得臃肿,复杂度提高了,从而影响代码的效率、开发人员的开发效率,项目的维护成等)
2.AOP主要应用于日志记录,性能统计,安全控制,事务处理等方面。它的主要意图就要将日志记录,性能统计,安全控制等等代码从
核心代码中清楚的划分出来。
3.AOP代理可以通过jdk动态代理实现,也可以通过cglib实现,默认是通过jdk动态代理实现的。jdk动态代理需要接口的支持,如果没有接口只有类,则使用cglib来实现。
jdk基于接口,cglib基于类
所谓代理设计模式:在代理模式中有个接口,接口中有个代理实现和一个真实实现,要用代理实现去代表真实实现。
一个接口,分别有一个真实实现和一个代理实现。静态代理中,真实实现和代理实现都是实现了同一个接口,并且把真实实现作为参数传递给代理实现去调用。
缺点:这种模式的代理类只能为一个接口的对象进行代理,这即是静态代理。要解决这样的问题,可以采用动态代理。
使用一个代理类便可以代理所有接口动态代理,通过代理类的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联,代理实现 都需要实现InvocationHandler接口,这个时候我们需要用到Proxy里面 的newProxyInstance需要有三个参数1.实现类,2.接口3.当前对象
1.切面(Aspect): 由切点(PointCut)和通知(Advice)组成,它既包括横切逻辑的定义,也包括了连接点的定义。
2.切点(Pointcut):一个切点定位多个类中的多个方法。(定义类或者方法的)
3.通知也叫增强(Advice):由方位和横切逻辑构成,所谓的方位指的是前置通知,后置通知,返回后通知,环绕通知,抛出异常后通知
4.连接点(JoinPoint):由切点和方位构成,用来描述在在哪些类的指定方法之前或之后执行
方位:
<1>.前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异
常)。
<2>.返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
<3>.抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
<4>后置通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
<5>环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。
环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
文件通常是由一连串的字节或字符构成,组成文件的字节序列称为字节流,组成文件的字符序列称为字符流。Java中根据流的方向可以分为输入流和输出流。输入流是将文件或其它输入设备的数据加载到内存的过程;输出流恰恰相反,是将内存中的数据保存到文件或其他输出设备,详见下图:
文件是由字符或字节构成,那么将文件加载到内存或再将文件输出到文件,需要有输入和输出流的支持,那么在Java语言中又把输入和输出流分为了两个,字节输入和输出流,字符输入和输出流,见下表:
InputStream是字节输入流,InputStream是一个抽象类,所有继承了InputStream的类都是字节输入流,主要了解以下子类即可:
主要方法介绍:
void |
close() |
abstract int |
read() |
int |
read(byte[] b) |
int |
read(byte[] b, int off, int len) |
所有继承了Reader都是字符输如流
主要方法介绍
abstract void |
close() |
int |
read() |
int |
read(char[] cbuf) |
abstract int |
read(char[] cbuf, int off, int len) |
所有继承了OutputStream都是字节输出流
主要方法介绍
void |
close() |
void |
flush() |
void |
write(byte[] b) |
void |
write(byte[] b, int off, int len) |
abstract void |
write(int b) |
示例代码:
所有继承了Writer都是字符输出流
主要方法介绍
Writer |
append(char c) |
abstract void |
close() |
abstract void |
flush() |
void |
write(char[] cbuf) |
abstract void |
write(char[] cbuf, int off, int len) |
void |
write(int c) |
void |
write(String str) |
void |
write(String str, int off, int len) |
缓冲流主要是为了提高效率而存在的,减少物理读取次数,缓冲流主要有:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter,并且BufferedReader提供了实用方法readLine(),可以直接读取一行,BuffereWriter提供了newLine()可以写换行符。
67.从数组中获取到最大的数据?
方式有很多
(递归)
通过先取出数组中的第一个值 然后用for依次循环是数组中的值是否大于第一个值如果大于第一个值 取出在用for循环 循环以后的值 按照这种方式找到数组中最大的值
工作流2.0的定义是:实现工作过程管理的自动化、智能化和整合化。工作流2.0最主要的特征就是可以灵便的实现数据整合和数据统计,消除信息孤岛,既能实现OA办公系统内部工作流之间的数据整合,如借款与报销、预算与决算等,又能实现OA办公系统工作流与其他业务系统之间的数据整合,如HR、ERP、CRM等。工作流2.0能彻底的弥补工作流1.0的不足,它不但实现OA办公系统内部的数据整合,也实现OA办公系统和第三方应用系统之间的数据整合。
如果给工作流1.0打上标签的话,那就是“无纸化、重复工作、流程孤岛、系统孤岛、数据孤岛”;工作流2.0对应的便是“智能化、效率质量提升、外部数据整合、消除信息孤岛、内部数据整合”。毫无疑问,工作流2.0更加智能,更加整合,能够实现数据的同步交换和共享的特征更受用户欢迎,能有效帮助企业简化多余流程,是未来工作流技术发展的方向。
69.
JVM -- java virtual machine
JVM就是我们常说的java虚拟机,它是整个java实现跨平台的 最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可 以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解 释给本地系统执行。
JVM 是 Java 平台的基础,和实际的机器一样,它也有自己的指令集,并且在运行 时操作不同的内存区域。 JVM 通过抽象操作系统和 CPU 结构,提供了一种与平台无关的代码执行方法,即与特殊的实现方 法、主机硬件、主机操作系统无关。但是在一些小的方面, JVM 的实现也是互不相同的,比如垃圾回收 算法,线程调度算法(可能不同 OS 有不同的实现)。
JVM 的主要工作是解释自己的指令集(即字节码)到 CPU 的指令集或 OS 的系统调用,保护用户免被恶意程序骚扰。 JVM 对上层的 Java 源文件是不关心的,它关注的只是由源文件生成的类文件( class file )。类文件的 组成包括 JVM 指令集,符号表以及一些补助信息。
JRE -- java runtime environment
JRE是指java运行环境。光有JVM还不能成class的 执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。 在JDK的安装目 录里你可以找到jre目录,里面有两个文件夹bin和lib,在 这里可以认为bin里的就是jvm,lib中则是jvm工 作所需要的类库,而jvm和 lib和起来就称为jre。所以,在你写完java程序编译成.class之后,你可以把这个.class文件 和jre一起打包发给朋友,这样你的朋友就 可以运行你写程序了。(jre里有运行.class的java.exe)
JRE 是 Sun 公司发布的一个更大的系统,它里面就有一个 JVM 。 JRE 就与具体的 CPU 结构和操作系统有关,我们从 Sun 下载 JRE 的时候就看到了不同的各种版本。同 JVM 一起组成 JRE 的还有一些 API (如 awt , swing 等)。 JRE 是运行 Java 程序必不可少的。
JRE ( Java Runtime Environment ),是运行 Java 程序必不可少的(除非用其他一些编译环境编译成.exe可执行文件……),JRE的 地位就象一台PC机一样,我们写好的Win32应用程序需要操作系统帮 我们运行,同样的,我们编写的Java程序也必须要JRE才能运行。
JRE里面有一个 JVM , JRE 与具体的 CPU 结构和操作系统有关,我们从 Sun 下载 JRE 的时候就看到了不同的各种版本,,同 JVM 一起组成 JRE 的还有 一些 API (如 awt , swing 等), JRE 是 运行 Java 程序必不可少的.
JDK -- java development kit
JDK是java开发工具包,基本上每个学java的人都会先在机器 上装一个JDK,那他都包含哪几部分呢?让我们看一下JDK的安装目录。在目录下面有 六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中,真正在运行java时起作用的 是以下四个文件夹:bin、include、lib、 jre。现在我们可以看出这样一个关系,JDK包含JRE,而JRE包 含JVM。
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
lib:类库
jre:java运行环境
(注意:这里的bin、lib文件夹和jre里的bin、lib是 不同的)总的来说JDK是用于java程序的开发,而jre则 是只能运行class而没有编译的功能。
eclipse、idea等 其他IDE有自己的编译器而不是用JDK bin目录中自带的,所以在安装时你会发现他们只要求你 选中jre路径就ok了。
三者联系
Java 喊出的带有标志性的口号“ Write Once , Run Anywhere (一次编写,到处运行)”,正是建立在 JRE 的基础之上。何以实现?就是在 Java 应用程序和操作系统之间增加了一虚拟层—— JRE 。
程序源代码不是直 接编译、链接成机器代码,而是先转化到字节码( bytecode ) 这种特殊的中间形式,字节码再转换成机器码或系统调用。前者是传统的编译方法,生成的机器代码就不可避免地跟特殊的操作系统和特殊的机器结构相关。
而 Java 程序的字节码文件可以放到任意装有 JRE 的计算机运行,再由不同 JRE 的将它们转化成相应的机器代码,这就实现了 Java 程序的可移植性。这样程序员也不用去 关心程序运行的具体环境,而可以专心编写软件。这种分层抽象、隐藏细节的思想在计算机科学中处处可见,比如机器组织结构的设计、网络协议的实现等。 Pascal 语言的发明者 Niklaus Wirth ,就富有预见性地指出应该有这样一种可移植的语言,其生成的中间代码可以在一台假想的机器( a hypothetical machine )上运行。
而 Java 虚拟机( Java virtual machine 或 JVM )就是这样的一台机器,它模拟实际处理器的结构,解释字节码。 怎么一会说是 JRE ,一会儿又成了 JVM ,两者是否同物不同名? 回答是否定的。
JRE的地位就象一台PC机一样,我们写好的Win32应用程序需要操作系统帮 我们运行,同样的,我们编写的Java程序也必须要JRE才能运行。
要运行Applet,在客户端必须安装有 JRE,即“运行时”,容易一点理解,就象所谓的“插件”,要开发JAVA应用程序\Web应用,就必须在服务器端安装相应的JVM+JDK 了(开发应用 Java web应用 时,客户端不需要安装任何的JVM)
如果你使用JAVA开发应用,就需要安装 JRE+JDK,就是 J2SE.
如果在客户端运行Applet,客户端浏览器必须嵌有JAVA JVM,如果没有,就需要安装,即: 在客户端创建JRE(运行时,包含JVM),而客户端是不需要做开发的,所以,JDK就没有必要安装 了。
不同版本的Applet在不同的JVM下可能无法正常运行,而Microsoft JVM只是Sun JVM的“低版本”,微软在windows xp/2003中干脆将JVM去掉了.
StringBuilder和StringBuffer都是可变字符串,前者线程不安全,后者线程安全。
StringBuilder和StringBuffer的大部分方法均调用父类AbstractStringBuilder的实现。其扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。
因为string是不可变的,所以绝对安全。StringBuilder实际上自身维护一个char[]数组,append是没有synchronized。StringBuffer的append等很多操作都是带有synchronized的,所以同样线程安全。
所以单线程字符串拼接一般采用StringBuilder,效率高。多线程环境则采用Stringbuffer,虽然安全,但是相对效率会低些。
StringBuffer 类被final 修饰所以不能继承没有子类
2、StringBuffer 对象是可变对象,因为父类的 value [] char 没有被final修饰所以可以进行引用的改变,而且还提供了方法可以修改被引用对象的内容即修改了数组内容。
3、在使用StringBuffer对象的时候尽量指定大小这样会减少扩容的次数,也就是会减少创建字符数组对象的次数和数据复制的次数,当然效率也会提升。存储过程
拦截器:需要门写一个普通类,继承interceptorAdapter,里面定义一个Adapter方法,我们那会儿怎么实现的呢,就是说当用户登陆成功以后,我都会把它登陆后的信息放到session里面,然后我们取的时候可以直接用看session里面有没有信息,如果有证明用户已经登陆了,就让他继续执行,如果没有信息springMVC里面的response.send redrecte这个方法让它重定向到登陆页面,还需在配置文件里面配置相应的标签,标签里面有两个属性:1,path(就是拦截器需要拦截的路径),然后就是引入咱们的定义的拦截器类,这也就简单实现咱们拦截器这样一个功能。
mybatis 是持久层它是ORM的一个实现,它是半自动化的框架,相比hibernate它的执行效率更高,它可以直接通过写sql这种方式来操作数据库,并且对sql的优化也比较方便,hibernate呢它是对jdbc的高度封装,所以对sql优化方面比较欠缺,在使用的时候呢,在它的配置文件里面的namespacse与咱们的接口进行匹配,像里面的resultMap(返回值集合)resultType(返回对象) parameterType(参数类型对象)parameterMap(参数集合)
服务端:
1.提供json视图/xml视图
2.提供jsonp方式的数据
3.webservice[服务端]
客户端:
1.ajax【jsonp】
2.httpclient
3.webservice[客户端]
webservice用于传统的企业[非互联网企业]【CXF】
SOA[面向服务编程][思想/理念]
webservice[实现方式]
xfire[技术框架]
cxf
axis2【很多公司】【掌握】
解决了 信息孤岛 的问题
跨语言,跨平台。
webService的三要素
1.wsdl(webservie描述语言):描述发布接口的信息
2.soap(简单对象访问协议)(webservice使用的协议):http+xml
3.uddi(查询和管理webservice)
cxf:
服务端的配置:
1.在web.xml中通过cxfServlet这个核心类对指定的url进行拦截
2.通过在接口上加入@webservice的注解
3.通过配置spring-cxf-server.xml这个配置文件进行接口的发布
4.在地址栏输入http://ip地址:端口号/项目名/web.xml中配置的servlet的url-pattern/spring-cxf-
server.xml中发布的接口的address?wsdl。【验证】
客户端的配置:【多种实现方式】【wsdl2java来生成客户端】【导入jar包】
1.配置环境变量 path=D:\java\apache-cxf-2.7.18\bin
2.wsdl2java -p 包名 -d 目标路径 服务器生成的接口路径
3.通过spring-cxf-client.xml来配置客户端
4.验证客户端代码以及服务端【单元测试】
简介
之前jsp-->controller-->service-->dao
webservice改变:
服务端:service-->dao
客户端:jsp-->controller-->远程service
httpclient/json视图 改变:
服务端:controller-->service-->dao
客户端:jsp-->controller-->service-->通过httpclient调用远程的json视图
ajax jsonp 改变:
服务端:controller-->service-->dao
客户端:jsp-->ajax jsonp