<?xml version="1.0" encoding="GBK"?>
<project name="hibernate" basedir="." default="">
    <property name="src" value="src"/>
    <property name="dest" value="classes"/>

    <path id="classpath">
        <fileset dir="../../lib">
            <include name="**/*.jar"/>
        </fileset>
        <pathelement path="${dest}"/>
    </path>

    <target name="compile" description="Compile all source code">
        <delete dir="${dest}"/>
        <mkdir dir="${dest}"/>
        <copy todir="${dest}">
            <fileset dir="${src}">
                <exclude name="**/*.java"/>
            </fileset>        
        </copy>
        <javac destdir="${dest}" debug="true" includeantruntime="yes"
            deprecation="false" optimize="false" failonerror="true">
            <src path="${src}"/>
            <classpath refid="classpath"/>
            <compilerarg value="-Xlint:deprecation"/>
        </javac>
    </target>

    <target name="run" description="Run the main class" depends="compile">
        <java classname="lee.ProductManager" fork="yes" failonerror="true">
            <classpath refid="classpath"/>
        </java>
    </target>

</project>
drop database if exists hibernate;

create database hibernate;

use hibernate;

CREATE TABLE category_inf (
  category_id bigint(20) NOT NULL auto_increment,
  name varchar(255) default NULL,
  eff_start_date datetime default NULL,
  eff_end_date datetime default NULL,
  PRIMARY KEY  (category_id)
);
INSERT INTO category_inf VALUES
(1,'it产品', ADDDATE(now() , - 200) , ADDDATE(now() , 20)),
(2,'工业产品', ADDDATE(now() , - 180) , ADDDATE(now() , 34)),
(3,'输出设备', ADDDATE(now() , - 223) , ADDDATE(now() , 42));

CREATE TABLE product_inf (
  product_id bigint(20) NOT NULL auto_increment,
  product_name varchar(255) default NULL,
  stock_number int(11) default NULL,
  eff_start_date datetime default NULL,
  eff_end_date datetime default NULL,
  PRIMARY KEY  (product_id)
);

INSERT INTO product_inf VALUES 
(1,'显示器',20040404 , ADDDATE(now() , - 90) , ADDDATE(now() , 20)),
(2,'键盘',20040219 ,  ADDDATE(now() , - 78) , ADDDATE(now() , 19)),
(3,'机箱',20040915 , ADDDATE(now() , - 56) , ADDDATE(now() , 15));


CREATE TABLE product_category (
  category_id bigint(20) NOT NULL,
  product_id bigint(20) NOT NULL,
  PRIMARY KEY  (product_id,category_id),
  KEY FKA0303E4E64F7AABC (category_id),
  KEY FKA0303E4E142E1558 (product_id),
  FOREIGN KEY (product_id) REFERENCES product_inf(product_id),
  FOREIGN KEY (category_id) REFERENCES category_inf (category_id)
);

INSERT INTO product_category VALUES 
(1,1),
(1,3),
(2,1),
(2,2),
(3,1),
(3,2),
(3,3);
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- hibernate-configuration是配置文件的根元素 -->
<hibernate-configuration>
    <session-factory>
        <!-- 指定连接数据库所用的驱动 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 指定连接数据库的url,其中hibernate是本应用连接的数据库名 -->
        <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
        <!-- 指定连接数据库的用户名 -->
        <property name="connection.username">root</property>
        <!-- 指定连接数据库的密码 -->
        <property name="connection.password">32147</property>
        <!-- 指定连接池里最大连接数 -->
        <property name="hibernate.c3p0.max_size">20</property>
        <!-- 指定连接池里最小连接数 -->
        <property name="hibernate.c3p0.min_size">1</property>
        <!-- 指定连接池里连接的超时时长 -->
        <property name="hibernate.c3p0.timeout">5000</property>
        <!-- 指定连接池里最大缓存多少个Statement对象 -->
        <property name="hibernate.c3p0.max_statements">100</property>
        <property name="hibernate.c3p0.idle_test_period">3000</property>
        <property name="hibernate.c3p0.acquire_increment">2</property>
        <property name="hibernate.c3p0.validate">true</property>
        <!-- 指定数据库方言 -->
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <!-- 根据需要自动创建数据库 -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 显示Hibernate持久化操作所生成的SQL -->
        <property name="show_sql">true</property>
        <!-- 将SQL脚本进行格式化后再输出 -->
        <property name="hibernate.format_sql">true</property>
        <!-- 罗列所有持久化类的类名 -->
        <mapping class="org.crazyit.app.domain.Category"/>
        <mapping class="org.crazyit.app.domain.Product"/>
    </session-factory>
</hibernate-configuration>
package lee;

import org.hibernate.*;
import org.hibernate.cfg.*;
import org.hibernate.service.*;
import org.hibernate.boot.registry.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author  Yeeku.H.Lee kongyeeku@163.com
 * @version  1.0
 */
public class HibernateUtil
{
    public static final SessionFactory sessionFactory;

    static
    {
        try
        {
            // 使用默认的hibernate.cfg.xml配置文件创建Configuration实例
            Configuration cfg = new Configuration()
                .configure();
            // 以Configuration实例来创建SessionFactory实例
            ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySettings(cfg.getProperties()).build();
            sessionFactory = cfg.buildSessionFactory(serviceRegistry);
        }
        catch (Throwable ex)
        {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    // ThreadLocal可以隔离多个线程的数据共享,因此不再需要对线程同步
    public static final ThreadLocal<Session> session
        = new ThreadLocal<Session>();

    public static Session currentSession()
        throws HibernateException
    {
        Session s = session.get();
        // 如果该线程还没有Session,则创建一个新的Session
        if (s == null)
        {
            s = sessionFactory.openSession();
            // 将获得的Session变量存储在ThreadLocal变量session里
            session.set(s);
        }
        return s;
    }

    public static void closeSession()
        throws HibernateException
    {
        Session s = session.get();
        if (s != null)
            s.close();
        session.set(null);
    }
}
package lee;

import org.hibernate.Transaction;
import org.hibernate.Session;

import java.util.*;
import java.text.SimpleDateFormat;

import org.crazyit.app.domain.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author  Yeeku.H.Lee kongyeeku@163.com
 * @version  1.0
 */
public class ProductManager
{
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args)
        throws Exception
    {
        ProductManager mgr = new ProductManager();
        mgr.test();
        HibernateUtil.sessionFactory.close();
    }

    private void test() throws Exception
    {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();

        // 启动effectiveDate过滤器,并设置参数
        session.enableFilter("effectiveDate")
            .setParameter("asOfDate", new Date());
        // 启动category过滤器,并设置参数
        session.enableFilter("category")
            .setParameter("catId", 2);
        // 查询所有Product实体,不加任何筛选条件,但effectiveDate过滤器会起作用
        List list = session.createQuery("from Product as p").list();     //
        for (Object obj : list)
        {
            Product p = (Product)obj;
            System.out.println(p.getName());
            // 获取Product对象关联的Category试题,2个过滤器会起作用。
            System.out.println("----" + p.getCategories());     //
        }
        tx.commit();
        HibernateUtil.closeSession();
    }
}
package org.crazyit.app.domain;

import javax.persistence.*;
import org.hibernate.annotations.FilterDefs;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.Filters;


import java.util.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author  Yeeku.H.Lee kongyeeku@163.com
 * @version  1.0
 */
@FilterDefs({
// 定义名为effectiveDate的过滤器,该过滤器支持1个date类型的参数
@FilterDef(name="effectiveDate"
    , parameters={@ParamDef(name="asOfDate" , type="date")}),
// 定义名为category的过滤器,该过滤器支持1个int类型的参数
@FilterDef(name="category"
    , parameters={@ParamDef(name="catId" , type="int")})
})
@Entity
@Table(name="product_inf")
// 使用effectiveDate过滤器对Product实体使用数据过滤
@Filter(name="effectiveDate"
    , condition=":asOfDate BETWEEN eff_start_date AND eff_end_date")

public class Product
{
    @Id @Column(name="product_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    // 定义产品名
    @Column(name="product_name")
    private String name;
    // 定义股票号属性,该属性可标识该产品
    @Column(name="stock_number")
    private int stockNumber;
    // 定义生效开始的时间
    @Column(name="eff_start_date")
    private Date effectiveStartDate;
    // 定义失效时间
    @Column(name="eff_end_date")
    private Date effectiveEndDate;
    // 定义该产品所属的种类
    @ManyToMany(targetEntity=Category.class)
    @JoinTable(name="product_category"
        , joinColumns=@JoinColumn(name="product_id")
        , inverseJoinColumns=@JoinColumn(name="category_id"))
    // 对该关联实体的抓取使用effectiveDate、category进行数据过滤
    @Filters({
        @Filter(name="effectiveDate"
            , condition=":asOfDate BETWEEN eff_start_date and eff_end_date"),
        @Filter(name="category"
            , condition="category_id = :catId")
    })
    private Set<Category> categories
        = new HashSet<>();

    // 无参数的构造器
    public Product()
    {
    }
    // 初始化全部成员变量的构造器
    public Product(String name , int stockNumber
        , Date effectiveStartDate , Date effectiveEndDate)
    {
        this.name = name;
        this.stockNumber = stockNumber;
        this.effectiveStartDate = effectiveStartDate;
        this.effectiveEndDate = effectiveEndDate;
    }

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    // stockNumber的setter和getter方法
    public void setStockNumber(int stockNumber)
    {
        this.stockNumber = stockNumber;
    }
    public int getStockNumber()
    {
        return this.stockNumber;
    }

    // effectiveStartDate的setter和getter方法
    public void setEffectiveStartDate(Date effectiveStartDate)
    {
        this.effectiveStartDate = effectiveStartDate;
    }
    public Date getEffectiveStartDate()
    {
        return this.effectiveStartDate;
    }

    // effectiveEndDate的setter和getter方法
    public void setEffectiveEndDate(Date effectiveEndDate)
    {
        this.effectiveEndDate = effectiveEndDate;
    }
    public Date getEffectiveEndDate()
    {
        return this.effectiveEndDate;
    }

    // categories的setter和getter方法
    public void setCategories(Set<Category> categories)
    {
        this.categories = categories;
    }
    public Set<Category> getCategories()
    {
        return this.categories;
    }

    // 根据stockNumber来重写hashCode()方法
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj != null && obj.getClass() == Product.class)
        {
            Product target = (Product)obj;
            return target.getStockNumber() == stockNumber;
        }
        return false;
    }

    // 根据stockNumber来重写hashCode()方法
    public int hashCode()
    {
        return stockNumber;
    }

    // 为产品添加一个所属的种类
    public void addCategory(Category category)
    {
        if ( category == null )
        {
            return;
        }
        this.categories.add(category);
        category.getProducts().add(this);
    }
}
package org.crazyit.app.domain;

import javax.persistence.*;
import org.hibernate.annotations.Filter;

import java.util.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author  Yeeku.H.Lee kongyeeku@163.com
 * @version  1.0
 */
@Entity
@Table(name="category_inf")
// 对Category实体使用数据过滤
@Filter(name="effectiveDate"
    , condition=":asOfDate BETWEEN eff_start_date and eff_end_date")
public class Category
{
    @Id @Column(name="category_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    private String name;
    @Column(name="eff_start_date")
    private Date effectiveStartDate;
    @Column(name="eff_end_date")
    private Date effectiveEndDate;
    @ManyToMany(targetEntity=Product.class, mappedBy="categories")
    private Set<Product> products
        = new HashSet<>();

    // 无参数的构造器
    public Category()
    {
    }
    // 初始化全部成员变量的构造器
    public Category(String name , Date effectiveStartDate , Date effectiveEndDate)
    {
        this.name = name;
        this.effectiveStartDate = effectiveStartDate;
        this.effectiveEndDate = effectiveEndDate;
    }

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    // effectiveStartDate的setter和getter方法
    public void setEffectiveStartDate(Date effectiveStartDate)
    {
        this.effectiveStartDate = effectiveStartDate;
    }
    public Date getEffectiveStartDate()
    {
        return this.effectiveStartDate;
    }

    // effectiveEndDate的setter和getter方法
    public void setEffectiveEndDate(Date effectiveEndDate)
    {
        this.effectiveEndDate = effectiveEndDate;
    }
    public Date getEffectiveEndDate()
    {
        return this.effectiveEndDate;
    }

    // products的setter和getter方法
    public void setProducts(Set<Product> products)
    {
        this.products = products;
    }
    public Set<Product> getProducts()
    {
        return this.products;
    }

    // 判断两个种类是否相等
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if(obj.getClass() == Category.class)
        {
            Category target = (Category)obj;
            return name.equals(target.getName())
                && effectiveStartDate.equals(target.getEffectiveStartDate())
                && effectiveEndDate.equals(target.getEffectiveEndDate());
        }
        return false;
    }

    // 生成hashCode的方式以名字的hashCode加上
    // 生效开始日期hashCode,再加生效结束日期的hashCode
    public int hashCode()
    {
        int result;
        result = name.hashCode();
        result = 29 * result + (effectiveStartDate != null ?
            effectiveStartDate.hashCode() : 0);
        result = 29 * result + (effectiveEndDate != null ?
            effectiveEndDate.hashCode() : 0);
        return result;
    }


}