2018年3月25日学习笔记

时间:2021-06-24 14:01:07

实现Product和Category多对一的关系

1.在Product类中增加Category属性

2.在Product.hbm.xml中设置Category多对一的关系

<many-to-one name="category" class="Category" column="cid" />

name="category"对应Product类中的category属性

class="Category"表示对应Category类

column="cid"表示指向category_表的外键,即cid是category_表的外键

3.在hibernate.cfg.xml中增加Category的映射(与Product相似)

增加了一个新的Category对象c1,并将其设置成id=8的product的category

Category c =new Category();

         c.setName( "c1" );
         s.save(c);
         
         Product p = (Product) s.get(Product. class , 8 );
         p.setCategory(c);
         s.update(p)

实现Category和Product一对多的关系

1.在Product中增加一个Set的集合

2.在Category.hbm.xml中增加one-to-many的映射

<set name="products" lazy="false">
<key column="cid" not-null="false" />
<one-to-many class="Product" />
</set>

lazy=“false”表示不使用延迟加载

not-null=false表示Product相对于Category的外键是cid且可以为空

实现Product和User之间多对多的关系

1.User中维护一个Product的集合

2.在相应的.hbm.xml中增加了many-to-many的映射

<set name="products" table="user_product" lazy="false">

             < key column = "uid" />
             < many-to-many column = "pid" class = "Product" />
         </ set >    

突然发现并不一定要用SQL语句手动创建表而只需要在文件中进行配置就可以了……

果然在教程的评论里发现有人和我有一样的疑问……

解释是:在hibernate.cfg.xml配置文件里有一个 <property name="hbm2ddl.auto">update</property>, 会导致表结构自动创建和修改,以前只以为update是自动更新相关数据的意思,没想到还有自动创建表的功能

还有额外的收获是有人注意到了虽然User和Product保持着多对多的关系,但是product的user属性却是null,这体现出了两者之间的关系只能通过中间表来体现,这就是和一对多,多对一关系的不同之处了

Hibernate任何对数据有改动的操作,都应该放在事务里面,如前文提到的那样,这要求MySQL是支持InnoDB的

Hibernate的延迟加载

属性延迟加载:当使用load方法来获取对象的时候,只有当访问了这个对象的属性,Hibernate才会到数据库中查询,否则并不会访问数据库。

关系的延迟加载:当要获取category_表的信息的时候,并不会查询product_表,只有通过category获取product的时候,才会进行对于product_表的查询。

级联操作:在没有配置级联的时候,删除分类,其分类下对应的产品并不会被删除

级联有四种类型:1.all:所有操作都执行级联操作;2.none:所有操作都不支持级联操作

3.delete:删除时执行级联操作;在Category中:

<set name="products" cascade="delete" lazy="false">

4.save-update:保存和更新时执行级联操作

级联操作通常用于one-many和many-to-many上,几乎不会用在many-one上

<set name="products" cascade="save-update" lazy="false">

会把没有添加到数据库里的瞬时状态的产品对象持久化

Hibernate的一级缓存是在Session上,二级缓存是在SessionFactory上

Hibernate使用Criteria进行分页查询

Criteria c= s.createCriteria(Product.class);

         c.add(Restrictions.like( "name" , "%" +name+ "%" ));
         c.setFirstResult( 2 );
         c.setMaxResults( 5 );

表示从第二条数据开始,一共查询五条数据

get和load两种获取方式:对于id不存在的情况,get方法会返回null,load方法会抛出异常

1. 获取的是否是同一个session对象
openSession每次都会得到一个新的Session对象
getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象
2. 事务提交的必要性
openSession只有在增加,删除,修改的时候需要事务,查询时不需要的
getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭

Hibernate有缓存机制,可以通过用id作为key把product对象保存在缓存中

同时hibernate也提供Query的查询方式。假设数据库中有100条记录,其中有30条记录在缓存中,但是使用Query的list方法,就会所有的100条数据都从数据库中查询,而无视这30条缓存中的记录

N+1是什么意思呢,首先执行一条sql语句,去查询这100条记录,但是,只返回这100条记录的ID
然后再根据id,进行进一步查询。

如果id在缓存中,就从缓存中获取product对象了,否则再从数据库中获取

s.beginTransaction();

  
         String name = "iphone" ;
         
         Query q =s.createQuery( "from Product p where p.name like ?" );
         
         q.setString( 0 , "%" +name+ "%" );
        
         Iterator<Product> it= q.iterate();
         while (it.hasNext()){
             Product p =it.next();
             System.out.println(p.getName());
         }
        
         s.getTransaction().commit();

突然联想到基于1的和基于0的,返回查询发现是PreparedStatement模糊查询是基于1的

PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00)
返回查询总数: s.beginTransaction();
  
         String name = "iphone" ;
         
         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);
         s.getTransaction().commit();
乐观锁:
<version name="version" column="ver" type="int"></version>

增加一个version字段,用于版本信息控制。这就是乐观锁的核心机制。

比如session1获取product1的时候,version=1。 那么session1更新product1的时候,就需要确保version还是1才可以进行更新,并且更新结束后,把version改为2。

注意: version元素必须紧跟着id后面,否则会出错。

1. 假设数据库中产品的价格是10000,version是10
2. session1,session2分别获取了该对象
3. 都修改了对象的价格
4. session1试图保存到数据库,检测version依旧=10,成功保存,并把version修改为11

5. session2试图保存到数据库,检测version=11,说明该数据已经被其他人动过了。 保存失败,抛出异常

C3P0连接池

Hibernate的注解:本来放在.hbm.xml中的文件映射信息,不用配置文件而改用注解来完成

点击打开链接

MVC

仅仅使用Servlet的短处:不仅要准备数据,还要准备HTML,可读性很差,写起来也很麻烦

仅仅使用JSP的短处:写Java代码不如在Servlet中方便

结合Servlet和JSP

public class HeroEditServlet extends HttpServlet {
 
     protected void service(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         int id = Integer.parseInt(request.getParameter( "id" ));
         Hero hero = new HeroDAO().get(id);
         request.setAttribute( "hero" , hero);
         request.getRequestDispatcher( "editHero.jsp" ).forward(request, response);
     }
}

实现获取数据然后跳转到jsp页面

<%@ page language= "java" contentType= "text/html; charset=UTF-8"
     pageEncoding= "UTF-8" import = "java.util.*,bean.*,java.sql.*" %>
 
<form action= 'updateHero' method= 'post' >
     名字 : <input type= 'text' name= 'name' value= '${hero.name}' > <br>
     血量 :<input type= 'text' name= 'hp' value= '${hero.hp}' > <br>
     伤害: <input type= 'text' name= 'damage' value= '${hero.damage}' > <br>
     <input type= 'hidden' name= 'id' value= '${hero.id}' >
     <input type= 'submit' value= '更新' >
</form>

不做查询数据库的事情,直接获取从HeroEditServlet传过来的Hero对象

MVC Model View Controller

控制器的作用就是把不同的数据,显示在不同的视图上

DAO:

public HeroDAO() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

把驱动的初始化的方法放在HeroDAO中

提供一个getConnection()的方法返回连接:所有的数据库操作都需要事先拿到一个数据库连接Connection

验证用户是否登录

从session中取出userName,如果是空,就表示用户没有登录,或者登录已经超过了30分钟。 客户端跳转到login.html,让用户重新登陆

struts

1.所有的访问都会被web.xml中配置的Struts的Filter所拦截

2.拦截之后,就进入Struts的工作流程

3.访问的地址是/index,根据Struts按照struts.xml的配置,服务器跳转到index.jsp

4.显示index.jsp的内容

在struts中也可以获取Servlet包中的request和response对象

struts中的Session有两个
一个是传统的servlet包下的HttpSession
另一个是Struts中自己定义的Session

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

新的Session的获取办法是
Map m = ActionContext.getContext().getSession();
这个session以Map类的形式出现,其中的值和HttpSession中的值是同步的

struts的专属标签库

form标签用于提交数据

< s:form action = "addProduct" >
 
   < s:textfield name = "product.name" label = "product name" />
   < s:submit value = "Submit" />
 
</ s:form >

提供s:iterator用于遍历一个集合中的数据

1.为ProductAction增加list()方法

为ProductAction增加一个products属性,类型是List,并提供get()和set()方法

为ProductAction增加一个list()方法,为products添加3个product对象,并返回list

2.在struts.xml中配置路径listProduct,并返回list.jsp

通配符匹配

拦截器:

package com.how2java.interceptor;
 
import java.util.Date;
 
import com.how2java.action.ProductAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
 
public class DateInterceptor extends AbstractInterceptor {
 
     public String intercept(ActionInvocation invocation) throws Exception {
        ProductAction action = (ProductAction)invocation.getAction();
        action.setDate( new Date());
        return invocation.invoke();
     }
}

表单验证

注解