这一个月的个人学习总结

 

1.struts+spring+hibernate框架学习及使用:

 

        a.struts2主要负责接收网页中表单提交的数据,然后通过 Action 进行处理,再 Forward 到对应的网页;

        

        b.spring相当于一个大容器,将struts2和hibernate整合进来。spring负责业务层管理,主要利用IoC和AoP对action,service,dao,数据访问源以及声明式事务等管理;

        

        c.hibernate主要负责持久化层,完成数据库的 crud 操作。

        

2.struts2学习:

 

        1.Struts2基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互,Struts2框架的绝大部分功能都是通过拦截器来完成的,

        当FilterDispatch拦截到用户请求后,大量拦截器将会对用户请求进行处理,然后调用定义的Action类中的方法进行处理请求,其工作流程如下:

      

        (1)  用户访问页面,客户端(Client)向Action发用一个请求(Request);

 

        (2)  Container通过web.xml映射请求,并获得控制器(Controller)的名字

 

        (3)  容器(Container)调用Struts2核心过滤器(StrutsPrepareAndExecuteFilter)。在Struts2(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter。

 

        (4)  控制器(Controller)通过ActionMapper获得Action的信息

 

        (5)  控制器(Controller)调用ActionProxy

 

        (6)  ActionProxy读取struts.xml文件获取action和interceptor stack的信息。

 

        (7)  ActionProxy把request请求传递给ActionInvocation

 

        (8)  ActionInvocation依次调用action和interceptor

 

        (9)  根据action的配置信息,产生result

 

        (10) Result信息返回给ActionInvocation

 

        (11) 产生一个HttpServletResponse响应

 

        (12) 产生的响应行为发送给客服端。

        

下面是流程图:

      



        2.流程源码剖析:

        

         1)StrutsPrepareAndExecuteFilter-> void init(FilterConfig filterConfig)方法进行初始化操作,并调用核心方法voiddoFilter(ServletRequest req, ServletResponse res, FilterChain chain),

           在该方法中:

a.      处理了HttpServletRequest和HttpServletResponse;

 

b.      获取ActionMapping,ActionMapping: String name, String method, Stringextension, private Map<String, Object> params, private Result result;

 

                           c.整个框架最核心的方法:executeAction(request, response, mapping)

                           

         2)executeAction(request,response, mapping) -> serviceAction(request, response, mapping)serviceAction 询问ActionMapper调用相应的action处理该请求 -> 解析mapping中的参数,交给ActionProxy 来处理,通过代理模式执行ActionProxy

           执行源码:

          

           if (mapping.getResult() != null) {

               Result result = mapping.getResult();

               result.execute(proxy.getInvocation());

           } else {

               proxy.execute();

           }

                           

        3)voidexecute(ActionInvocation invocation) -> Interceptor, action, result ->HttpServletResponse

           

         3.在项目学习开发中,多个action可以采用动态方法调用:

               

        1)通过设置method属性,method="相应的方法名";

                  

                  2)通过感叹号,首先需要在strut2.xml中添加<constantname="struts.enable.DynamicMethodInvocation"value="true"></constant>,当请求/login!*.action时,就会调用相应的action;

                  

                  3)通配符: actionname=*; result={1},第三种比较常用

                           

        4.Struts2使用json

 

当struts2返回json数据时,首先添加struts2-json-plugin依赖, 然后是在struts.xml中,在package中extends修改为extends="json-default" ,最后添加相应的<result name="json"type="json">

        

3.hibernate学习:

        

        1.hibernate工作原理以及步骤:

        

          a.读取并解析配置文件;

          b.读取并解析映射信息,SessionFactory;

          c.创建事物Transaction

          d.持久化操作

          e.提交事物

          f.关闭Session

          g.关闭SessionFactory

   

          在项目开发中对于POJO的映射一般都会采用注解的方式进行映射。

        

    2.hibernate的三种状态:

        

                  1)瞬时对象: 对于刚创建的一个对象,如果Session中和数据库中都不存在改对象,那么该对象就是瞬时对象;

                  

                  2)离线对象: 离线对象就是数据库中存在该对象,但该对象有没有被session托管

                  

                  3)持久化对象: 瞬时对象调用save方法,或者离线对象调用update方法变成持久化对象。即对改对象的任何修改,都会在提交事物时才会与之进行比较,如果不同则发送一个条update语句,否则就不会发送语句。

                  

        3.hibernate中的get方法和load方法的区别:

        

                  1)返回结果:

                    load方法查不到的话会抛出org.hibernate.ObjectNotFoundException异常;

         get方法查不到的话会返回null。

                   

                  2)查询机制上对比:

                     load方法会首先去Session缓存中查,查找到则返回,查找不到回判断是否为lazy(延迟加载),不是lazy会抛出异常,是lazy会先创建代理对象,当真正操作该对象时会访问数据库,查找不到抛出异常;

                     get方法会直接去数据库中查询,查找不到返回null

                  

                  3)本质区别

                           load方法,hibernate会认为该对象一定在数据库中存在,可以放心使用代理对象来延迟加载,当真正操作该对象时才会访问数据库,查不到抛出异常;

                           get方法会先查缓存,没有查数据库,没有返回nul,get方法一定是返回的是实体对象。

                           

        4.hibernate3和hibernate4的稍微区别:

                  

                  1)对于hibernate3的SessionFactory的属性参数bean配置使用的包是:org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;

                  

                     对于hibernate4的SessionFactory的属性参数bean配置使用的包是:org.springframework.orm.hibernate4.LocalSessionFactoryBean

                  

                   2)hibernate3中的获取的Session的getSession方法已经被摒弃

                           hibernate4中通过getSessionFactory().getCurrentSession()来获取一个Session

                  

        5.在项目开发中一般都让DaoImplement继承HibernateSupport,然后调用getHibernateTemplate(),使用封装好的简单CRUD

        

        

4.protobuf学习:

 

        protobuf就是一种数据传输的方式,跟json一样可以取代xml来进行数据的传输,与json相比在大数据的条件下,protobuf数据压缩所在的大小优于json。

        

        首先添加依赖:protobuf-java

        

        测试:

        

        protoc文件:

        

        package tutorial;

 

        option java_package="com.ssh.protobuftest.protobuf";

 

        option java_outer_classname="PersonProbuf";

 

        message Person{

                  required string name =1;

                  required int32 id=2;

                  optional string email=3;

                  

                  enum PhoneType{

                           MOBILE = 0;

                           HOME = 1;

                           WORK = 2;

                  }

                  

                  message PhoneNumber{

                           required string number=1;

                           optional PhoneType type=2[default = HOME];

                  }

                  

                  repeated PhoneNumber phone=4;

                  

                  message CountryInfo{

                           required string name=1;

                           required string code=2;

                           optional int32 number=3;

                  }

        }

 

 

        message AddressBook{

                  repeated Person person=1;

        }

        

        测试java代码:

        

        import java.util.List;

        import com.google.protobuf.InvalidProtocolBufferException;

        import com.ssh.protobuftest.protobuf.PersonProbuf.Person;

        import com.ssh.protobuftest.protobuf.PersonProbuf.Person.PhoneNumber;

 

        public class TestPb {

                  public static void mian(String[] args) {

                           Integer a=new Integer(2);

                           a.equals(2);

                           

                           //java_outer_classname.message name.Builder builder=java_outer_classname.messagename.newBuilder();

                           PersonProbuf.Person.Builder builder=PersonProbuf.Person.newBuilder();

                           

                           //builder进行一系列的get/set方法

                           builder.setEmail("kkk@email.com");

 

                           builder.setId(1);

 

                           builder.setName("TestName");

                           

                           builder.

                           

                           //使用add是在一个message还有一个message,即类似内部类

                           //addxxx用来给内部message赋值,其中set可以连续set

                           addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().

                                              setNumber("131111111").setType(PersonProbuf.Person.PhoneType.MOBILE));

 

                           builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().

                                              setNumber("011111").setType(PersonProbuf.Person.PhoneType.HOME));

 

                           //调用build方法转换成message对象

                           Person person=builder.build();

                           

                           //转成二进制流并保存在数组中

                           byte[] buf=person.toByteArray();

                           

                           

                           try {

                                    Person person2 = PersonProbuf.Person.parseFrom(buf);

 

                                    System.out.println(person2.getName() + ", " + person2.getEmail());

 

                                    List<PhoneNumber> lstPhones = person2.getPhoneList();

                                    

                           for (PhoneNumber phoneNumber : lstPhones) {

                                    

                                    System.out.println(phoneNumber.getNumber());

                           }

 

                           } catch (InvalidProtocolBufferException e) {

 

                                    e.printStackTrace();

                                    

                           }

                                    System.out.println(buf);

                  }

        }

        

 

5.MySql性能优化学习:

        

1.优化方案:


1)建立索引,使用索引查询(类型,最好选择基本类型,eg: INT,建立的字段选择,选择修改少,查询多的字段);
2)sql语句优化,最好不要过多张表关联,少使用函数和%等导致索引失效的sql;
3)表结构(水平拆分,垂直拆分);
4)引擎选择;
5)使用缓存
6)主从结构(读写分离),主库抗写压力,通过从库来分担读压力,对于写少读多的应用。

2.因为mysql默认采用的是InnoDB,所以提高InnoDB的性能很有必要:


1)innodb_flush_log_at_trx_commit 设为2
当设为0,能使性能明显提升,但是不安全;
当设为1,每次插入数据时都会自定提都会刷新到磁盘中,性能低

同理set AUTOCOMMIT=0;

2)开启慢查询日志show.log
增加参数: log-queries-not-using-indexes 将所有没有走索引的sql都会记录到show.log中,方便找出没有使用索引的sql语句;


3)使用explian查看sql语句的执行形式,判断是否有走索引,访问的行数rows;

4)提高查询query_cache命中率;

5)关闭skip_name_resolve,减少逆向解析dns的消耗;

6)innodb_log_file_size 设为50%,对于高并发写入性能高,(太大recovery变慢,太小影响查询性能)

7)根据业务要求,考虑是否可关闭xa事务(分布式事务),有效减少磁盘刷新次数

8)反范式使用冗余字段,增加一些必要的冗余字段,以空间换时间增加开发的工作量和维护量

9)增加中间表,对需要经常联合查询的表,建立中间表以提高查询效率。通过建立中间表,把需要经常联合查询的数据插入到中间表中,然后将原来的联合查询改为对中 间表的查询,以此来提高查询效率。

10)垂直拆分,有时候有些字段使用频率很低或者字段的数据类型比较大,那么可以考虑垂直拆分的方法,把不常用的字段和大字段拆分出去,就是从业务角度来看,将 关联性不强的数据拆分到不同的instance上,从而达到消除瓶颈的目标。对于重复读类型比较多的场景,我们还可以加一层cache(缓存),来减少对DB的压力

11)水平拆分,水平拆分之后,任何实例都只有全量的1/n的数据,eg: 将userinfo拆分为3个cluster,每个cluster持有总量的1/3数据,3个cluster数据的总和等于一份完整                    数据,但会给应用增加复杂度,它通常在查询时需要多个表名,查询所有数据需要union操作

下面是两张分布式计算的数据库框架图,顺便也呈现出来:

 



上述内容若有错误,欢迎各位拍砖指出,

 

 


 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐