后端框架原理学习(官网+how2j方式)

spring 框架 以前学写的教程

what?

  • IOC(inversion of Control )反转控制 就是创建、管理所有的Java对象,这些Java对象被称为Bean。实现解耦。
  • DI(Dependency Inject)依赖注入 就是再创建一个对象的同时给啦加点东西 可以是另一个对象 也可以是其他东西。
  • AOP(Aspect Oriented Program)面向切面编程 将通用业务从具体逻辑中分离出来

    why?

  • 简化对象创建呗

    how?

  • applicationContext类是什么?实用的Bean工厂 。
  • ClassPathXmlApplicationContext类是什么?从类路径ClassPath中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作。
  • FileSystemXmlApplicationContext是什么?从指定的文件系统路径中寻找指定的XML配置文件
  • XmlWebApplicationContext是什么?从Web应用中寻找指定的XML配置文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    /*IOC代码举例*/
    //applicationContext.xml
    <bean name="c" class="类的相对路径">
    <property name="类的属性字段" value="属性值"></property>
    </bean>
    //testSpring 测试类
    //实例化Bean工厂applicationContext 得到context获取要创建的对象实例 可写多个配置文件
    applicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
    Category c=(Category)context.getBean("c");
    System.out.println(c.getName);

    /*DI*/
    <bean name="c" class="类的相对路径/Category">
    <property name="类的属性字段" value="属性值"></property>
    </bean>
    <bean name="P" class="类的相对路径/Product">
    <property name="类的属性字段" value="属性值"></property>
    //创建一个属性字段为Category字段 指向name为c的Bean
    <property name="Category" ref="c"></property>
    </bean>
    //testSpring 测试类
    Product p = (Product) context.getBean("p");
    System.out.println(p.getName());
    System.out.println(p.getCategory().getName());

    /*注解 代替xml写IOC/DI*/
    //<context:component-scan base-package="com.how2java.pojo"/>
    @Component("p")
    class Product{}
    @Resource(name="c")/@Autowrite
    private Category category;

    /*AOP*/
    //.xml

SpringMVC 框架

what?

  • 加入啦spring的mvc(模型 视图 分排器 分离)框架
  • spring

Hibernate 框架

what?

  • orm对象关系映射框架 解决 关系型数据库中加载和存储对象时我们要面临以下五个不匹配的问题
  • SessionFactory /Session /httpSession 区别
  • SessionFactory SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,生产session的工厂
  • session 是用来表示,应用程序和数据库的一次交互(会话)。在这个Session中,包含了一般的持久化方法(CRUD)
  • Persistence 持久化 就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。
  • 对象状态:瞬时(类没与session发生联系 jvm关啦 对象没啦) 持久(session创建没关 数据库有记录) 脱管(session关啦 数据库留下记录)
  • 一个主配置文件(数据库连接信息 加载所有表配置文件) 多个表配置文件(建立表与实体类的对应 主键 属性 集合 一对多关系的配置)
  • eg:Category c = (Category) s.get(Category.class, 1); Set ps = c.getProducts();
  • 与s.get()不同,当使用load的方式来获取对象的时候,只有访问了这个对象的属性,hibernate才会到数据库中进行查询。否则不会访问数据库。
  • 关系的懒加载(配置文件),Category c = (Category) s.get(Category.class, 1);不会查询product表。
  • 什么是级联? 简单的说,没有配置级联的时候,删除分类,其对应的产品不会被删除。 但是如果配置了恰当的级联,那么删除分类的时候,其对应的产品都会被删除掉。级联通常用在one-many和many-to-many。
  • 一级缓存:第一次通过id=1获取对象的时候,session中是没有对应缓存对象的,所以会在”log1”后出现sql查询语句。
    第二次通过id=1获取对象的时候,session中有对应的缓存对象,所以在”log2”后不会出现sql查询语句
  • 二级缓存 存在sessionFactory里面 hibernate本身不提供二级缓存,都是使用第三方的二级缓存插件。

    1
    2
    3
    4
    5
    6
    7
    8
    //没有开启二级缓存的情况
    创建了两个Session
    在第一个Session里
    第一次获取id=1的Category 会执行SQL语句
    第二次获取id=1的Category,不会执行SQL语句,因为有一级缓存
    在第二个Session里
    获取id=1的Category,会执行SQL语句,因为在第二个Session,没有缓存该对象。
    所以总共会看到两条SQL语句。
  • EhCache提供的二级缓存 (配置虐) 在第二个Session里无查询语句。

  • Criteria进行分页查询

    1
    2
    3
    4
    5
    6
    String name="xxx";
    Criteria c=s.createCriteria(具体查询类名.class)
    c.add(Restrictions.like("name","%"+name+"%"));
    c.setFristResult(2)//第三条数据开始
    c.setMaxResult(5)//数据总数
    List<类名>lists=c.list();
  • 对于id不存在的对象的处理 都通过id=500去获取对象 1. get方式会返回null 2. load方式会抛出异常

  • Hibernate有两种方式获得session

    1
    2
    3
    4
    5
    6
    7
    8
    openSession和getCurrentSession
    他们的区别在于
    1. 获取的是否是同一个session对象
    openSession每次都会得到一个新的Session对象
    getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象
    2. 事务提交的必要性
    openSession只有在增加,删除,修改的时候需要事务,查询时不需要的
    getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭
  • N+1是什么意思呢,首先执行一条sql语句,去查询这100条记录,但是,只返回这100条记录的ID(关键点)
    然后再根据id,进行进一步查询。如果id在缓存中,就从缓存中获取product对象了,否则再从数据库中获取。

    1
    2
    3
    4
    5
    6
    7
    首先通过Query的iterator把所有满足条件的Product的id查出来

    然后再通过it.next()查询每一个对象
    如果这个对象在缓存中,就直接从缓存中取了
    否则就从数据库中获取

    N+1中的1,就是指只返回id的SQL语句,N指的是如果在缓存中找不到对应的数据,就到数据库中去查
  • 查询总数:首先还是准备一个有统计函数的语句select count(*) from ….根据这条SQL语句创建一个Query对象,调用Query对象的uniqueResult()方法,返回一个long型的数据,即查询总数。

    1
    2
    3
    4
    Query q =s.createQuery("select count(*) from Product p where p.name like ?");
    q.setString(0, "%"+name+"%");
    long total= (Long) q.uniqueResult();
    System.out.println(total);
  • 乐观锁 (配置虐) 防止多个事务操作统一对象导致数据库数据不一致()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    故意创造一个场景来制造脏数据。
    1. 通过session1得到id=1的对象 product1
    2. 在product1原来价格的基础上增加1000
    3. 更新product1之前,通过session2得到id=1的对象product2
    4. 在product2原来价格的基础上增加1000
    5. 更新product1
    6. 更新product2
    最后结果是product的价格只增加了1000,而不是2000

    假设数据库中产品的价格是10000,version是10
    2. session1,session2分别获取了该对象
    3. 都修改了对象的价格
    4. session1试图保存到数据库,检测version依旧=10,成功保存,并把version修改为11
    5. session2试图保存到数据库,检测version=11,说明该数据已经被其他人动过了。 保存失败,抛出异常
  • 数据库连接池:建立数据库连接时比较消耗时间的,所以通常都会采用数据库连接池的技术来建立多条数据库连接,并且在将来持续使用,从而节约掉建立数据库连接的时间
    hibernate本身是提供了数据库连接池的,但是hibernate官网也不推荐使用他自带的数据库连接池。c3p0连接池 配置虐。(只有在高并发量的情况下性能才会体现)

  • 简而言之,就是提升性能 节约时间的。
  • 注解方式:不用写*表与类/类之间的关联配置文件 让主配置文件加载具体类 具体类中通过注解建立表与实体类的对应 主键 属性 集合 一对多关系的配置
  • A->B类 一对多 在A类使用@onetomany 一定在b类@ManyToOne
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /*一对多注解*/
    //1.为Category再加product集合,并提供getter和setter
    //2.给getProducts方法加上一对多注解
    //3.fetch=FetchType.EAGER 表示不进行延迟加载
    @Entity
    @Table(name = "category_")
    public class Category {
    Set<Product>products;
    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="cid")
    public Set<Product> getProducts() {
    return products;
    }


    }
    /*多对一注解*/
    //1.@JoinColumn(name="cid") 表示关系字段是cid
    @ManyToOne
    @JoinColumn(name="cid")
    public Category getCategory() {
    return category;
    }

    Category c = (Category) s.get(Category.class, 1);
    Set<Product> ps = c.getProducts();

how?

  • 1.关系型数据库配置文件(数据库信息(mysql dialect方言 hbm2.ddl show_sql…)然后是mapping 映射到具体 表与类的关联配置)
  • 2.表与类的关联配置(表名 属性一一映射)
  • 3.根据配置文件创建SessionFactory(初始化hibernate) 开启一个session Session s=sf.openSession();
  • 3.在session上 开启一个事务s.beginTransction(); s.save(对象实例);
  • 4.s.close(); sf.close();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*关系型数据库配置文件hibernate.cfg.xml*/
<hibernate-configuration>
<session-factory>
<!--database configuration-->
<property name="connection.driver_class">com.mysql.jdbc.Driver </property>
<property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8 </property>
<property name="connection.password">admin </property>
<property name="connection.username">root </property>
<!--sql dialect 为啦适应数据库改变-->
<property name="dialect">org.hibernate.dialect.MYSQLDialect </property>
<!--一个线程管理一个事务-->
<property name="current+session_context_class">thread </property>
<property name="show_sql">true </property>
<property name="hbm2ddl.auto">update </property>
<mappring resource="表与类的关联配置的相对路径"></mappring>
</session-factory>
</hibernate-configuration>

/*表与类/类之间的关联配置*/
<hibernate-mapping package="类所在包的相对路劲">
<class name="类名" table="数据库表名">
//主键id 类表对象 数据库本体自增长方式
<id name="id" clumn="id">
<generator class="native"></generator>
</id>
<property name="类属性" clumn=“表字段”></property>
<property name="类属性" clumn=“表字段”></property>
</class>
</hibernate-mapping>

/*使用*/
<!--根据配置创建session对象-->
SesssionFactory SessionFactory=new Configuration.configure().buildSessionFactory();
session s=SessionFactory.openSession();
s.beginTransction()
s.sava();
s.close()
SessionFactory.close()

//基本curd s.get(类名.class,id) ......
/*hibernate的原生sql查询*/
Query q=s.createSQLQuery(sql);
List<类名> lists=q.list();

/*一对多关系*/
/*另一个类的配置文件*/
/*第一个类->另一个类 eg:一对多*/
<hibernate-mapping package="另一个类所在包的相对路劲">
<class name="类名" table="数据库表名">
//主键id 类表对象 数据库本体自增长方式
<id name="id" clumn="id">
<generator class="native"></generator>
</id>
<property name="类属性" clumn=“表字段”></property>
<property name="类属性" clumn=“表字段”></property>
<
</class>
</hibernate-mapping>

struct 框架

what?

  • web.xml就是前端控制器的配置 可以用Filter拦截请求并交给-> struct.xml分配到具体的类执行。
  • session存放会议数据的容器 并提供啦操作数据的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struts中的Session有两个
    一个是传统的servlet包下的HttpSession
    另一个是Struts中自己定义的Session

    传统的servlet包下的session的获取办法是:
    ServletActionContext.getRequest().getSession();
    使用该方法,需要在eclipse的项目中导入servlet-api.jar,可以在右边下载

    新的Session的获取办法是
    Map m = ActionContext.getContext().getSession();
    这个session以Map类的形式出现,其中的值和HttpSession中的值是同步的
    product.setName("iphone7");
    Map m = ActionContext.getContext().getSession();
    m.put("name", product.getName());
    return "show";
  • iterrator 迭代器标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //.jsp
    <s:iterator value="products" var="p" status="st">
    <tr>
    <td>${p.id}</td>
    <td>${p.name}</td>
    <td>${st.index}</td>
    <td>${st.count}</td>
    <td>${st.first}</td>
    <td>${st.last}</td>
    <td>${st.odd}</td>
    <td>${st.even}</td>
    </tr>
    </s:iterator>
  • form 标签

    1
    2
    3
    4
    5
    6
    <form id="addProduct" name="addProduct" action="addProduct.action" method="post">
    //struct.xml
    <action name="addProduct" class="com.how2java.action.ProductAction" method="add">
    <result name="input">addProduct.jsp</result>
    <result name="show">show.jsp</result>
    </action>