OneStack

The Blog Powered By jessyon


  • 首页

  • 归档

  • 标签

AccountManage开发记录

发表于 2016-08-16   |  

整体概况

完成这个面试题前前后后用了10天,因为期间也在准备另外一个实习的面试。加上指定的技术栈我不是特别熟悉,所以花费了比较多的时间来学习,但是依然只完成了指定功能的80%左右。
第一天就遇到了很大的麻烦,由于spring-boot-starter-parent版本不是用的最新版,一直启动不了main。后来又遇到了json数据传输的问题,不知道spring-boot怎样处理json数据。
后来又遇到了包扫描的坑,之前没有在注入的bean之前加上@Component标签,造成bean没有注入,main无法启动等一系列问题。

关于maven生成的jar包的说明

在AccountManage-0.0.1-SNAPSHOT.jar所在的位置启动命令行,输入
java -jar AccountManage-0.0.1-SNAPSHOT.jar
可启动内置的tomcat服务器,在浏览器输入
http://localhost:8080/findAll
就可以出现以下界面,我使用的是本地mysql数据库,所以访问数据可能会有点问题。

核心代码

    @SpringBootApplication
    @Controller
    public class Application {

    @Autowired(required=true) 
    private AccountManageService accountManageService;

    // freemarker
    @RequestMapping("/hello")
    public String web(Map<String, Object> model) {
        model.put("time", new Date());
        return "hello";// 返回的内容就是templetes下面文件的名称
    }

    //
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public void update(@RequestBody AccountManage account) {
        accountManageService.update(account);
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public void add(@RequestBody AccountManage account) {
        System.out.println(account);
        accountManageService.add(account);
    }

    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @ResponseBody
    public void delete(@RequestBody AccountManage account) {
        accountManageService.deletById(account.getId());
    }

    @RequestMapping("/findAll")
    public String findAll(@ModelAttribute("model") ModelMap model) {
        List<AccountManage> list = accountManageService.findAll();
        model.addAttribute("infos", list);
        model.addAttribute("time", new Date().toLocaleString());
        System.out.println(new Date().toLocaleString());
        return "hello";
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


Dao层

    @Component
    @Repository
    public class AccountManageDaoImpl implements AccountManageDao{
        @Autowired
        private JdbcTemplate jdbcTemplate;

        public List<AccountManage> findAll() {
            String sql = "select * from info";
            return (List<AccountManage>) jdbcTemplate.query(sql, new RowMapper<AccountManage>() {

                public AccountManage mapRow(ResultSet rs, int rowNum) throws SQLException {
                    AccountManage accountManage = new AccountManage();
                    accountManage.setCountType(rs.getString("count_type"));
                    accountManage.setCreateTime(rs.getString("create_time"));
                    accountManage.setId(rs.getString("id"));
                    accountManage.setLastTime(rs.getString("last_time"));
                    accountManage.setName(rs.getString("name"));
                    accountManage.setStatus(rs.getString("status"));
                    accountManage.setRemark(rs.getString("remark"));
                    System.out.println(accountManage.toString());
                    return accountManage;
                }
            });
        }

        public void add(AccountManage account) {
            jdbcTemplate.update(
                    "insert into info(id,name,create_time,status,count_type,last_time,remark ) values(?,?,?,?,?,?,?)",
                    account.getId(), account.getName(), account.getCreateTime(), account.getStatus(),
                    account.getCountType(), account.getLastTime(), account.getRemark());
        }

        public void deleteById(String id) {
            jdbcTemplate.update("delete from info where id = ?", id);
        }

        @Override
        public void update(AccountManage account) {
            jdbcTemplate.update(
                    "update  info(name,create_time,status,count_type,last_time,remark ) values(?,?,?,?,?,?) where id=?",
                     account.getName(), account.getCreateTime(), account.getStatus(),
                    account.getCountType(), account.getLastTime(), account.getRemark(),account.getId());
        }
    }

我是如何整合SSH的(三)CRM总结

发表于 2016-06-01   |  

前述

这个周一直在逐步地完成临摹一个CRM系统的工作,并且每一小版本的工作都通过SVN记录下来。这个周初步了解学习了linux系统,选用的版本是Centos6.5,并且学会了搭建JavaEE所需要的环境,包括Tomcat7、jdk1.7、eclise,svn等基本环境。还学会了如何通过SSH远程登录服务器,如何在windows和linux之间交换数据。

小项目:CRM

练习步骤

1.确定需求
1.1登录 (基本流程、登录拦截器、校验)
1.2员工管理

  • 查询所有
  • 添加(ajax级联)
  • 更新(标签回显)
  • 条件查询
    1.3课程类别
  • 查询所有(条件 + 分页)
  • 添加或更新

2.根据需求创建ER图,并在数据库中添加数据

3.在Eclips中创建CRM项目,并且将项目添加SVN版本控制器。

4.添加Spring、Hibernate、struts2等相关的jar包

5.对应ER图,创建相应的JavaBean,并且为相应的Bean添加hibernate配置文件。

<hibernate-mapping>
<class name="com.jessyon.crm.classes.domain.CrmClass" table="crm_class">
    <id name="classId">
        <generator class="uuid"></generator>
    </id>

    <property name="name"></property>
    <property name="beginTime">
        <column name="beginTime" sql-type="datetime"></column>
    </property>
    <property name="endTime">
        <column name="endTime" sql-type="datetime"></column>
    </property>

    <property name="status"></property>
    <property name="totalCount"></property>
    <property name="upgradeCount"></property>
    <property name="changeCount"></property>

    <property name="runoffCount"></property>
    <property name="remark"></property>
    <property name="uploadTime">
        <column name="uploadTime" sql-type="datetime"></column>
    </property>

    <property name="uploadPath"></property>
    <property name="uploadFilename"></property>

    <many-to-one name="courseType" class="com.jessyon.crm.coursetype.domain.CrmCourseType" column="courseTypeId"></many-to-one>
</class>
</hibernate-mapping>

6.配置spring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
                          http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/tx 
                          http://www.springframework.org/schema/tx/spring-tx.xsd
                          http://www.springframework.org/schema/aop 
                          http://www.springframework.org/schema/aop/spring-aop.xsd
                          http://www.springframework.org/schema/context 
                          http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 配置公共项 -->
<!-- 1 加载properties文件 -->
<context:property-placeholder location="classpath:jdbcInfo.properties"/>

<!-- 2 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}"></property>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    <property name="user" value="${jdbc.user}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

<!-- 3 session工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.current_session_context_class">thread</prop>
            <prop key="javax.persistence.validation.mode">none</prop>
        </props>
    </property>
    <property name="mappingLocations" value="classpath:com/jessyon/crm/*/domain/*.hbx.xml"></property>

<!-- 4 事务管理 -->
<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 4.2 事务详情  -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="add*"/>
        <tx:method name="save*"/>
        <tx:method name="update*"/>
        <tx:method name="delete*"/>
        <tx:method name="find*" read-only="true"/>
        <tx:method name="*" read-only="true"/>
    </tx:attributes>
</tx:advice>
<!-- 4.3 aop编程  
-->
<aop:config proxy-target-class="true">
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.jessyon.crm.*.service..*.*(..))"/>
</aop:config>


<!-- 包含其他子模块 -->
<!-- 员工 ,部门, 职务-->
<!-- <import resource="applicationContext-staff.xml"/>
<import resource="applicationContext-department.xml"/>
<import resource="applicationContext-post.xml"/>
<import resource="applicationContext-coursetype.xml"/> -->
</beans>

applicationContext-courseType.xml
其他的相关的配置文件,比如department、post、staff的配置文件都是以下格式

    <bean id="courseTypeDao" class="com.jessyon.crm.coursetype.dao.impl.CourseTypeDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- service -->
<bean id="courseTypeService" class="com.jessyon.crm.coursetype.service.impl.CourseTypeServiceImpl">
    <property name="courseTypeDao" ref="courseTypeDao"></property>
</bean>

7.配置struts2

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 常量 -->
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.ui.theme" value="simple"></constant>

<!-- 公共项 其他子模块都会继承common -->
<package name="common" namespace="/" extends="struts-default">
    <!-- 配置拦截器 -->
    <interceptors>
        <interceptor name="loginInterceptor" class="com.jessyon.crm.web.interceptor.LoginInterceptor"></interceptor>
        <interceptor-stack name="loginStack">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="loginInterceptor">
                <!-- 不需要拦截的方法,多个方法逗号隔开 -->
                <param name="excludeMethods">login</param>
            </interceptor-ref>
        </interceptor-stack>
    </interceptors>
    <!-- <default-interceptor-ref name="loginStack"></default-interceptor-ref> -->
    <global-results>
        <result name="login">/WEB-INF/pages/login.jsp</result>
    </global-results>
    <action name="uiAction_*_*">

            <result>/WEB-INF/pages/{1}/{2}.jsp</result>
    </action>
</package>

<!-- 包含其他子模块 -->
<include file="struts/struts-staff.xml"></include>
<include file="struts/struts-post.xml"></include>
<include file="struts/struts-department.xml"></include>
<include file="struts/struts-coursetype.xml"></include>
</struts>

struts2-courseType.xml
其他的相关的配置文件,比如department、post、staff的配置文件都是以下格式

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
struts>
<package name="coursetype" namespace="/" extends="common">
    <action name="courseTypeAction_*" class="com.jessyon.crm.coursetype.web.action.CourseTypeAction" method="{1}">
        <result name="findAll">/WEB-INF/pages/coursetype/listCourse.jsp</result>
        <result name="saveOrUpdateUI">/WEB-INF/pages/coursetype/addOrEditCourse.jsp</result>
        <result name="saveOrUpdate" type="redirectAction">
            <param name="namespace">/</param>
            <param name="actionName">courseTypeAction_findAll</param>
        </result>
    </action>
</package>
</struts>

8.配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Mycrm</display-name>
  <filter>
      <filter-name>openSession</filter-name>
      <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
  </filter>

  <filter-mapping>
      <filter-name>openSession</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/applicationContext*.xml</param-value>
  </context-param>

  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <filter>
          <filter-name>struts2</filter-name>
          <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>

  <filter-mapping>
          <filter-name>struts2</filter-name>
          <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

我是如何整合SSH的(二)

发表于 2016-05-25   |  

前述

这个周在初步了解SSH整合流程,同时以项目为驱动继续学习SSH。在网上找了一个CRM系统来临摹,同时辅助学习SVN版本控制器。因为之前并没有很多版本控制的概念,所以在接触SVN的时候,遇到了很多问题。CRM系统目前已经完成了登录功能,之后会通过CRM再熟悉SSH的CRUD。

新知识点

  • spring配置中,可以在applicationContext.xml中通过来引入applicationContext-user.xml配置文件。
  • struts2配置中,指定package的name=”common”,其他struts2配置文件可以通过继承包名为common下的所有内容。
  • struts2配置中,可以通过来引入struts包下的struts-staff.xml配置文件中的所有内容。
  • MD5加密,可以通过MessageDigest messageDigest=MessageDigest.getInstance(“MD5”)初始化消息摘要算法
    通过byte[] md5value = messageDigest.digest(value.getBytes());对String类型的字符串进行加密。
    得到内容是10进制的,通过BigInteger bigInteger = new BigInteger(1,md5value); bigInteger.toString(16);转换成16进制。
  • SVN开启服务,打开命令行,输入svnserve -d -r f:\svn开启服务(f:\svn为仓库目录)。
  • 在svnserve.conf文件的20、27、36行,将注释打开,开启svn权限配置。
    auth-access = write
    password-db = passwd
    authz-db = authz 这三行前面不能有任何空格。
  • 在passwd文件下添加用户 user1 = 1234 user1为用户名,1234为密码。
  • 在authz文件下配置权限
    [crm:/] 配置crm文件夹的访问权限
    jessyon = rw 用户jessyon有读写权限
    *=r 其他所有用户为只读权限
  • check out到本地文件,在文件夹中右键SVN checkout弹出窗口,输入svn://localhost:3690/crm便可以将服务器上的内容checkout下来。

特别注意

在eclipse中,新建的web项目并没有jstl.jar和standard.jar这两个包,如果是myeclipse中的项目导入到eclipse中并且用到了jstl,那么需要额外导入这两个jar包。

我是如何整合SSH的(一)

发表于 2016-05-20   |  

概述

在之前一段时间内,我断断续续在课余时间学习了struts2、hibernate3、spring和其他javaEE的关键技术。由于之间一直呆在实验室帮老师做一个其他的项目,并没有很认真地学习javaEE,掌握的知识可能并不是很牢靠,所以通过整合SSH这个过程来提高我对JavaEE的认知。

Spring整合Hibernate3之注册案例

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//定义User
private Integer id;
private String username;
private String pwd;
private Integer age;
private Date birthday;

//User.hbx.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.bean.User" table="user">
<id name="id">
<generator class="native"></generator>
</id>
<property name="username"></property>
<property name="pwd"></property>
<property name="age"></property>
<property name="birthday" type="date"></property>
</class>
</hibernate-mapping>

//UserDaoImpl ,继承自HibernateDaoSupport,可以使用hibernate的模版
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
public void addUser(User u) {
this.getHibernateTemplate().save(u);
}
}

//UserService层,这一层和以前没有任何改变
public class UserServiceImpl implements UserService {

private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void register(User u) {
this.userDao.addUser(u);
}
}

//用注册一个用户来测试Spring是否已经整合了hibernate
public class SSHTest {
@Test
public void testAdd(){
User u = new User();
u.setUsername("jessyon");
u.setPwd("1234");
u.setAge(18);
u.setBirthday(new Date());

String xmlPath="applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.register(u);
}

//和单独使用hibernate一样,需要在src下创建一个hibernate.cfg.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<!-- 1.基本4项 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///ssh</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">jessyon6233834</property>

<!-- 方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

<!-- sql语句 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>

<!-- 6 取消bean校验 -->
<property name="javax.persistence.validation.mode">none</property>

<!-- 添加映射文件 -->
<mapping resource="com/ssh/bean/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>

//Spring的配置都保存在applicationContext.xml里面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 1 获得session工厂
* 加载hibernate.cfg.xml 获得工厂
configLocation : 确定配置文件位置
-->

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>

<!-- 2 模板 -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- dao UserDao类里用到了hibernateTemplate,所以需要将之注入到dao里面-->
<bean id="userDao" class="com.ssh.daoimpl.UserDaoImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"></property>
</bean>

<bean id="userService" class="com.ssh.serviceimpl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>

<!-- 事务管理 ,需要将管理事务的session注入-->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="register"/>
</tx:attributes>
</tx:advice>

<!-- aop 执行service中的方法前,添加事务管理。如果不加这句话,就相当于执行了rollback,没有commit-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ssh.service..*.*(..))"/>
</aop:config>
</beans>

//也可以不使用hibernate.cfg.xml,那么applicationContext需要微调

//使用c3p0作为数据源(连接池)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///ssh"></property>
<property name="user" value="root"></property>
<property name="password" value="jessyon6233834"></property>
</bean>

//session工厂的内容变多,不仅需要注入数据源,还要将hibernate.cfg.xml里的内容注入
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
<property name="mappingLocations" value="classpath:com/ssh/bean/*.hbm.xml"></property>
</bean>

我是如何学习Spring的(三)--AspectJ

发表于 2016-05-18   |  

Aspect概述

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

  • AspectJ是一个基于Java语言的AOP框架
  • Spring2.0以后新增了对AspectJ切点表达式支持
  • AspectJ注解 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
  • 常用自定义内容开发。例如:性能监控等
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
59
60
61
62
63
64
65
66
67
68
69
//自定义切面类
public class MyAspect {

public void mybefore(){
System.out.println("前置通知");
}
}


//Service接口类
public interface UserService {

public void addUser();
public void update();
}

//Service实例
public class UserServiceImpl implements UserService{

public void addUser() {
System.out.println("addUser");
}

public void update() {
System.out.println("update");
}
}

//测试类
@Test
public void Test01(){
String xmlPath = "com/jessyon/aspectj/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);

//从spring获得bean数据
UserService userService = (UserService) applicationContext.getBean("userService");
userService.addUser();
userService.update();
}

//beans.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">


<bean id="userService" class="com.jessyon.aspectj.UserServiceImpl"></bean> //配置一个Service类
<bean id="MyAspect" class="com.jessyon.aspectj.MyAspect"></bean> //配置一个自定义切面类
<aop:config> //配置aop
<aop:aspect ref="MyAspect"> //配置切面类,将自定义切面类注入进来

//定义切点,切点为包名为com.jessyon.aspectj下的任意参数,任意返回值的任意方法
<aop:pointcut expression="execution(* com.jessyon.aspectj.*.*(..))" id="myPointcut"/>
<aop:before method="mybefore" pointcut-ref="myPointcut"/> //定义切面类为前置通知,将myPointcut注入
</aop:aspect>
</aop:config>
</beans>


//测试结果(在每个方法执行前,都会打印"前置通知")

前置通知
addUser
前置通知
update

切入点表达式

execution(表达式) 用于确定方法(可以为不同的方法进行确定)
修饰符
public 修饰符公共

   *            任意修饰符
返回值
   String        返回字符串
   *            返回任意
包    
   com.jessyon.service                    指定包(某一个模块)
   com.jessyon.*.service                子模块(子文件夹)任意
   com.jessyon.service..                service目录当前目录 ,以及子目录(孙子)
   com.jessyon.*.service..                jessyon下所有的子模块,service目录所有目录
类
   UserService                指定类名
   User*                    以User开头类
   *Service                以Service结尾类
   *                        任意类
方法
   addUser                    指定方法
   add*                    add开头方法
   *User                    以User结尾方法
   *                        任意方法
参数列表
   ()                        没有参数
   (int)                    一个参数
   (int,int)                两个参数
   (..)                    参数任意

AspectJ通知类型

定义6中通知类型,掌握1种,知道4种,了解1种。

  • before:前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行
  • afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执行。必须在方法执行后才执行,所以可以获得方法的返回值。
  • around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行
  • afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
  • after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    public class MyAspect{

    public void myBefore(JoinPoint joinPoint){
    System.out.println("前置通知 :" + joinPoint.getSignature().getName());
    }

    public void myAfterReturning(JoinPoint joinPoint,Object ret){
    System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , " + ret);
    }

    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("环绕前");
    //执行目标方法
    Object obj = joinPoint.proceed();

    System.out.println("环绕后");
    return obj;
    }

    public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
    System.out.println("抛出异常通知:" + joinPoint.getSignature().getName() + " , " + e.getMessage());
    }

    public void myAfter(JoinPoint joinPoint){
    System.out.println("最终"+ joinPoint.getSignature().getName() );
    }

    }


    //注解版本
    @Component
    @Aspect
    public class MyAspect{

    //定义:公共切入点表达式。之后使用直接调用方法名
    @Pointcut("execution(* com.jessyon.annotation.*.*(..))")
    private void myPointCut(){}

    //@Before("execution(* com.jessyon.annotation.*.*(..))")
    public void myBefore(JoinPoint joinPoint){
    System.out.println("前置通知 :" + joinPoint.getSignature().getName());
    }

    //@AfterReturning(value="execution(* com.jessyon.annotation.*.*(..))",returning="ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
    System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , " + ret);
    }

    //@Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("环绕前");
    //执行目标方法
    Object obj = joinPoint.proceed();

    System.out.println("环绕后");
    return obj;
    }

    //@AfterThrowing(value="myPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
    System.out.println("抛出异常通知:" + joinPoint.getSignature().getName() + " , " + e.getMessage());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
    System.out.println("最终"+ joinPoint.getSignature().getName() );
    }
    }
    <!-- 注解aspectj 必须进行配置 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

我是如何学习Spring的(二)

发表于 2016-05-07   |  

简介

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
Spring是典型的控制层的框架,Model层有Hibernate、Mybatis等框架可选,View有Struts2、Spring MVC可供选择,然而Spring处于无法被替换控制层。

AOP

Aspect Oriented Programming(面向切面编程) 是继面向对象编程后的又一伟大创造。面向切面编程可以理解为程序的运行被切成了几段,每一段都加上不同的功能,加权限,加日志等等,AOP的核心是动态代理。

AOP的术语:

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合

  • beans.xml配置文件

    1
    2
    3
    4
    5
    6
    //Spring中配置bean的基本方法(IOC构造方法实例化)
    <bean id="u" class="com.spring.dao.impl.UserDaoImpl"></bean>
    //将userDao注入到userService()中
    <bean id="userService" class="com.spring.service.UserService">
    <property name="userDao" ref="u"></property>
    </bean>
  • 代理(proxy)类的实现,在method方法执行前,增加一个功能,beforeMethod()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    public class LogInterceptor implements InvocationHandler, org.springframework.cglib.proxy.InvocationHandler{

    private Object target; //定义代理对象

    public void beforeMethod(Method m){
    System.out.println(m.getName()+" start"); //在被代理对象执行前,先执行该方法
    }

    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {

    beforeMethod(method);
    method.invoke(target, args);
    return null;
    }
    }
  • 普通Dao对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    public interface UserDao {

    public void save(User u);
    public void delete();
    }

    public class UserDaoImpl implements UserDao{

    public void save(User u) {

    System.out.println("add user!");
    }

    public void delete() {

    System.out.println("delete user!");
    }
    }
  • 被代理的Service类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class UserService {

    private UserDao userDao;

    public void add(User user){
    userDao.save(user);
    }

    public UserDao getUserDao() {
    return userDao;
    }

    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    }
  • 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class UserServiceTest {

    @Test
    public void testAdd(){
    BeanFactory applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    UserService userService = (UserService) applicationContext.getBean("userService");

    User user= new User();
    user.setUserName("jessyon");
    user.setPassword("12346");
    userService.add(user);
    }
    @Test
    public void testProxy(){
    UserDao userDao= new UserDaoImpl();
    LogInterceptor li = new LogInterceptor();
    li.setTarget(userDao);
    UserDao userDaoProxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), new Class[]{UserDao.class}, li);
    userDaoProxy.save(new User());
    userDaoProxy.delete();
    }
    }
  • 执行结果

    1
    2
    3
    4
    5
    在每个方法执行前,都先执行了代理后,新增的方法
    save start
    add user!
    delete start
    delete user!
  • 注:BeanFactory和ApplicationContext的区别

  • ApplicationContext类继承了BeanFactory.
  • BeanFactory在使用到这个类的时候,getBean()方法的时候才会加载这个类.
  • ApplicationContext类加载配置文件的时候,创建所有的类.
  • ApplicationContext对BeanFactory提供了扩展:
    国际化处理
    事件传递
    Bean自动装配
    各种不同应用层的Context实现

我是如何学习Spring的(一)

发表于 2016-05-06   |  

简介

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

Spring优点

方便解耦,简化开发

Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理

AOP编程的支持

Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无需手动编程

方便程序的测试

Spring对Junit4支持,可以通过注解方便的测试Spring程序

方便集成各种优秀框架

Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

降低JavaEE API的使用难度

Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

基本概念

Dependency 依赖:一个类的实现需要用到另一个类。
Injection 注入:将一个类添加到另一个类中。
DI (Dependency Injection) 依赖注入:A类依赖B类,A类提供set接口,当需要B类时,通过接口,将B类传递给A类。
IOC (Inversion of Control) 控制反转:由以前的A类创建B类,转变为由第三方IOC容器(Spring)创建B类。A类不能直接创建B类,A类通过第三方IOC容器获取B类。

传统方式

传统方式创建 Model、Dao、DaoImpl、Service

  • User Model

    1
    2
    3
    4
    5
    public class User {
    private String username;
    private String password;
    //省略get、set方法
    }
  • User Dao

    1
    2
    3
    public interface UserDAO {
    public void save(User user);
    }
  • User DaoImpl

    1
    2
    3
    4
    5
    6
    public class UserDAOImpl implements UserDAO {
    public void save(User user) {

    System.out.println("user saved!");
    }
    }
  • User Service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class UserService {
    private UserDAO userDAO;
    public void add(User user) {
    userDAO.save(user);
    }
    public UserDAO getUserDAO() {
    return userDAO;
    }
    public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
    }
    }
1
2
3
//创建Service层,Service层调用DaoImpl的add()方法,add()调用Dao层的save()方法。
Service service= new Service();
service.add(u);

IOC方式

beans.xml配置一个bean

<beans>
    <bean id="u" class="com.dao.impl.UserDAOImpl" />          //配置一个简单类
    <bean id="userService" class="com.service.UserService" >  //配置一个userService
        <property name="userDAO" bean="u"/>     //为userService通过property配置一个setUserDao()方法,当调用setUserDao()方法时,将u这个bean传进去(注入)。
    </bean>
</beans>
``` bash
//IOC方式与传统方式得到的结果都一样,在控制台输出user saved!因为都执行了save(User)方法。
public class UserServiceTest {
    @Test
    public void testAdd() throws Exception {
        //1 加载配置文件,默认为beans.xml
        BeanFactory applicationContext = new ClassPathXmlApplicationContext(); 
        UserService service = (UserService)applicationContext.getBean("userService");    

        User u = new User();
        u.setUsername("zhangsan");
        u.setPassword("zhangsan");
        service.add(u);
    }
}

##

我是如何学习Hibernate的(六)

发表于 2016-05-05   |  

前述

缓存在操作系统中经常被使用,在CPU和内存之间有高速cache。在内存读取硬盘的时候也有缓存,也有相应的缓存页面置换算法: FIFO(First In First Out)先进先出、LRU(Least Recently Used)最近很少使用、 LFU(Least Frequently Used)最近不常被使用(命中率低)。在Hibernate中也有使用一级缓存和二级缓存来加快读取数据库的操作,节省开销。

一级缓存

一级缓存,又称为session级别的缓存。当获得一次会话,hibernate在session中创建多个集合(Map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用,没有再查询。

  • 缓存工作原理
  • 一级缓存是默认的,查询都将数据存放在一级缓存中。
  • 一级缓存缓存的是对象本身。
  • 一级缓存常用的API
    evict():用于对某个对象从session的一级缓存中清除
    clear():将一级缓存中所有对象全部清除
    flush():刷新一级缓存区的内容,使之与数据库数据保持同步。
    注意: 常用的Query方法中,query.list()是不使用一级缓存的,每次都是重新查询数据库的。

一级缓存的操作

//1 查询 id = 1
User user = (User) session.get(User.class, 1);
System.out.println(user);
//2 再查询 -- 不执行select语句,将从一级缓存获得
User user2 = (User) session.get(User.class, 1);   //此时 user 与user2是同一个对象

清除缓存

User user = (User) session.get(User.class, 1); 
System.out.println(user);
//清除
//session.clear();
session.evict(user);
// 一级缓存没有缓存对象,从数据库直接查询
User user2 = (User) session.get(User.class, 1); 
System.out.println(user2);    //此时user 与 user2 为两个不同对象

一级缓存的快照(备份)

快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与一级数据缓存必须一致。如果一级缓存修改,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存保存到数据库中。

  • 问题:一级缓存什么时候刷新?能否修改刷新时机?
    默认情况下,执行commit()时。当修改了一级缓存后,三种情况:session查询,手动刷新flush,commit底层自动flush

二级缓存

使用annotation配置缓存:

1
2
3
4
5
6
7
8
9
10
11
12
@Entity
//@BatchSize(size=5)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@region="gionName"
public class Category {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}

缓存策略(CacheConcurrencyStrategy)的取值

  • 只读缓存(Strategy:read only)(常用)
    如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。
  • 读写/缓存(Strategy:read/write)(常用)
    如果应用程序需要更新数据,那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。 如果在 JTA 环境中使用缓存,你必须指定 hibernate.transaction.manager_lookup_class 属性的值, 通过它,Hibernate 才能知道该应用程序中 JTA 的TransactionManager的具体策略。 在其它环境中,你必须保证在 Session.close()、或 Session.disconnect() 调用前, 整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate 内置的缓存策略并不支持锁定功能。
  • 非严格读/写缓存(Strategy:nonstrict read/write)
    如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。如果在 JTA 环境中使用该策略,你必须为其指定 hibernate.transaction.manager_lookup_class 属性的值,在其它环境中,你必须保证在Session.close()、或 Session.disconnect() 调用前,整个事务已经结束。
  • 事务缓存(transactional)
    Hibernate 的事务缓存策略提供了全事务的缓存支持,例如对 JBoss TreeCache 的支持。这样的缓存只能用于 JTA 环境中,你必须指定为其 hibernate.transaction.manager_lookup_class 属性。

    region的取值

    在ehcache.xml中,可以自定义缓存类型,比如:
    1
    2
    3
    4
    5
    6
    7
    <cache name="sampleCache1"
    maxElementsInMemory="10000" //最大缓存数量
    eternal="false" //是否能被清除
    timeToIdleSeconds="300" //300秒没被访问就被清除
    timeToLiveSeconds="600" //已经存在600秒就可以被清除
    overflowToDisk="true" //溢出时放在硬盘上
    />

那么@region=”sampleCache1”
配置文件中:
//不使用二级缓存
org.hibernate.cache.NoCacheProvider
//hibernate中默认的二级缓存ehcache
true
org.hibernate.cache.EhCacheProvider
//启用查询缓存
true

  • load默认使用二级缓存,iterate默认使用二级缓存
  • list默认往二级缓存加数据,但是查询的时候不使用
  • 如果要query用二级缓存,需打开查询缓存
    true
    调用Query的setCachable (true)方法指明使用二级缓存
    例如:session.createQuery(“from Category”).setCacheable(true).list();

我是如何学习Hibernate的(五)

发表于 2016-05-04   |  

前述

Hibernate中的级联关系和抓取策略是放在一起使用的,应当先搞清楚级联关系的一对一、多对一、一对多、多对多。再搞清楚抓取策略中的fetch、lazy的使用,然后再将二者结合一起使用。

多对一(重点) 、 一对一


多端维护关联关系,多端持有一个一端的引用,在多端加入一个外键,指向一端。
使用多个User对一个Group举例(Annotation版本+XML配置版本)
注意:使用Annotation配置,可以不用像以前一样配置XML文件,在hiberna.cfg.xml中需要使用:

1
2
<mapping class="com.hibernate.User" />
<mapping class="com.hibernate.Group" />

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
package com.hibernate;
// 多端:User类,省略不重要的包和get、set方法
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;

@ManyToOne
public Group getGroup() {
return group;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
}

XML主要配置:
<hibernate-mapping>
<class name="com.hibernate.User" table="t_user">
<id name="id">
<generator class="native"></generator>
</id>

<property name="name"></property>
<many-to-one name="group" column="groupId" />
</class>

</hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.hibernate;
// 一端:Group类,省略不重要的包和get、set方法
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
}

XML主要配置:
<class name="com.hibernate.Group" table="t_group">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<class>

多对一总结

  • 只需要在多端User的getGroup方法上端进行注解配置

    1
    2
    3
    4
    5
    @ManyToOne //多对一关联 User是多的一方 Group是一的一方
    @JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名
    public Group getGroup() {
    return group;
    }
  • xml:
    标签会在多端添加外键,相当于在数据库中添加外键,生成的表为:
    user(id,name,groupid),t_group(id,groupname)

  • 属性cascade

    取值all,none,save-update,delete,对象间的级联操作,只对增删改起作用.
    在存储时User时,设置了cascade=”all”会自动存储相应的t_group.而不用管user关联的对象(通常情况下会优先存储关联的对象,然后再存储user)。

多对一抓取策略

  • fetch取值:join select
    join:底层使用迫切左外连接,lazy无效。
    select:使用多条查询语句查询。
  • lazy取值:false、proxy、no-proxy
    false:不实用懒加载,在查询的时候把所有字段全部加载到缓存中。
    proxy:采用关联对象,类级别检索策略。

  • fetch=”select” lazy=”proxy”是否延迟,取决于关联对象所设定的类级别检索策略。比如:
    多端(User端):
    一端(Group端):
    同时查询User和Group会同时生成两条select语句。

多端(User端):
一端(Group端):
同时查询User和Group,先生成select User的语句,当使用到Group属性时,再生成select Group的语句。

我是如何学习Hibernate的(四)

发表于 2016-05-03   |  

前述

框架的出现是为了适应一些繁琐的重复的工作,从连接数据库到CRUD的实现,再到存储过程,事务。如果自己曾经从头到尾写过JDBC的实现,那么多半会怀疑人生。其实,在自己写JDBC的时候,可能很多人都违背DRY(Don’t Repeat Youself)的原则。框架出现的意义就是前辈们将自己踩过的坑填平,让后辈能够走得更平坦一些。

抓取策略

  • 立即检索:立即查询,在执行查询语句时,立即查询所有数据。
  • 延迟检索:延迟查询,在执行查询语句以后,在需要数据时再查询(懒加载)。
  • 类级别检索:当前类的属性获取是否需要延迟。
    get:立即检索
    Load:延迟检索,默认情况,如果只使用OID的值不进行查询,如果要使用其他属性值,将进行查询。
    Customer.hbm.xml
    lazy默认为true,如果设置为false则会立即检索(不使用代理)。
  • 关联级别检索:当前类关联的别一个类是否需要延迟。

    一对多、多对多

    容器提供了两个属性:fetch、lazy
    以Customer和Order作为例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.hibernate3;
    //Customer类及配置文件
    public class Customer {

    private Integer uid;
    private String name;
    private Set<Order> orderSet = new HashSet<Order>();
    }

    <hibernate-mapping>
    <class name="com.hibernate3.Customer" table="customer">
    <id name="uid" column="id" >
    <generator class="native" />
    </id>
    <set name="orderSet" fetch="select" lazy="false">
    <key column="customer_id" />
    <one-to-many class="com.hibernate3.Order"/>
    </set>
    <property name="name" column="name" />
    </class>
    </hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Order类及其配置文件
package com.hibernate3;

public class Order {

private Integer oid;
private Integer price;
private Customer customer;

<hibernate-mapping>
<class name="com.hibernate3.Order" table="t_order">
<id name="oid" column="id" >
<generator class="native" />
</id>
<many-to-one name="customer" class="com.hibernate3.Customer" column="customer_id">
</many-to-one>
<property name="price" />
</class>
</hibernate-mapping>

}
1
2
3
4
5
6
7
8
9
10
11
12
13
//业务逻辑
//1 查询订单
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer.getCname());

//2 查询客户订单数
Set<Order> orderSet = customer.getOrderSet();
System.out.println(orderSet.size());

//3 查询客户订单详情
for (Order order : orderSet) {
System.out.println(order);
}
  • fetch:确定使用SQL格式(Join fetching、Select fetching、Subselect fetching)
    Join:使用Outer join(外连接)来获取关联实例或者关联集合。当fetch=join时,lazy无效。
    Select:如果没有指定lazy=false,禁止延迟加载,那么当真正访问关联关系时,会执行另一条SQL。
    Subselect:另外发送一条SQL,抓去前面抓取到的所有实体对象的集合。当真正访问关联关系时,会执行另一条SQL。必须使用query,否则看不到效果

  • lazy:关联对象是否延迟(Immediate、Lazy collection、Extra-lazy)
    Immeaiate 立即抓取 (lazy=flase):当宿主被加载时,关联、集合属性被立即抓取。
    Lazy collection fetching 延迟加载集合 (lazy=true):直到应用程序对集合进行了一次操作时,集合才被抓取(默认)。
    Extra-lazy 集合抓取 (lazy=extra):对集合中的每个元素而言,都是直到需要时才进行访问数据库。(适用于非常大的集合)

  • fetch=”join”,lazy无效,底层会使用迫切左外连接,只是用一条select语句将所有的内容全部查询。

  • fetch=”select” lazy=”false” ,立即查询,先查询客户select,再查询订单select。(同时执行两条语句)
  • fetch=”select” lazy=”true” ,立即查询第一条语句,当需要Order数据时,再查询第二条。
  • fetch=”select” lazy=”extra” ,立即查询第一条语句,当需要时,第二条语句使用聚合函数select count(*)查询,一共三条语句。

fetch=”subselect” lazy=”和上面一样” ,将使用子查询。必须使用Query,不然看不到效果。
业务逻辑变为:

//1 查询客户
List<Customer> allCustomer = session.createQuery("from Customer").list();
Customer customer = allCustomer.get(0);
System.out.println(customer.getCname());

//2 查询客户订单数
Set<Order> orderSet = customer.getOrderSet();
System.out.println(orderSet.size());

//3 查询客户订单详情
for (Order order : orderSet) {
    System.out.println(order);
}
  • fetch=”subselect” lazy=”false” ,同时执行两条select,第二条使用子查询(select …from…where id in(select…))
  • fetch=”subselect” lazy=”true” ,第二条语句延迟查询。
  • fetch=”subselect” lazy=”extra” ,第二条语句使用聚合函数,第三条语句使用子查询。
1234
Jessyon

Jessyon

35 日志
35 标签
© 2016 Jessyon
由 Hexo 强力驱动
主题 - NexT.Pisces