liguofeng29’s blog

個人勉強用ブログだっす。

Hibernate - 試してみようサンプル

設定ファイル : 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>
        <!-- ドライバ -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 接続情報 -->
        <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">xxxx#</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>
        <!-- DB方言解消 -->
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <!-- 必要に応じて表生成? -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 生成SQL表示 -->
        <property name="show_sql">true</property>
        <property name="hibernate.format_sql">true</property>

        <!-- マッピングテーブル -->
        <mapping class="entity.Item"/>
    </session-factory>
</hibernate-configuration>

永久化クラス : Item.java

package entity;

import java.math.BigDecimal;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="m_item")
public class Item {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private BigDecimal price;

    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Dao親クラス : DaoSupport.java

package dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public abstract class DaoSupport {
    protected Session getSession() {
        // Configurationインスタンス化
        Configuration conf = new Configuration()
        // 引数なし : hibernate.cfg.xml
        // 引数あり : 引数の設定ファイル
            .configure();

        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
            .applySettings(conf.getProperties()).build();

        // SessionFactory生成
        SessionFactory sf = conf.buildSessionFactory(serviceRegistry);
        // Session生成
        Session session = sf.openSession();

        return session;
    }
}

ItemのDaoクラス : ItemDao.java

package dao;

import java.util.List;

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

import entity.Item;

public class ItemDao extends DaoSupport {

    public void save(Item item) {
        Session session = super.getSession();

        // TX開始
        Transaction tx = session.beginTransaction();
        session.save(item);
        tx.commit();
        session.close();
    }

    public Item load(Integer id) {
        Session session = super.getSession();

        // loadすると
        // Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Sessionが発生する
        // Item item = (Item) session.load(Item.class, id);
        Item item = (Item) session.get(Item.class, id);
        session.close();

        return item;
    }

    public void update(Item item) {
        Session session = super.getSession();

        // TX開始
        Transaction tx = session.beginTransaction();
        session.update(item);
        tx.commit();
        session.close();
    }

    public void delete(Item item) {
        Session session = super.getSession();

        // TX開始
        Transaction tx = session.beginTransaction();
        session.delete(item);
        tx.commit();
        session.close();
    }

    public List<Item> searchAll() {
        Session session = getSession();

        @SuppressWarnings("unchecked")
        List<Item> list = session.createCriteria(Item.class).list();

        return list;
    }
}

・登録テスト

import java.math.BigDecimal;

import dao.ItemDao;
import entity.Item;

public class TestEntity {
    public static void main(String[] args) {
        ItemDao itemDao = new ItemDao();

        Item item = new Item();
        // Item生成
        item.setPrice(new BigDecimal(100));
        item.setName("item01");

        // 登録
        itemDao.save(item);

//     // 更新
//     item.setPrice(new BigDecimal(200));
//     itemDao.update(item);
//
        // 検索
//     Item item2 = itemDao.load(1);
//     System.out.println(item2.getId());
//     System.out.println(item2.getName());
//     System.out.println(item2.getPrice());
//
//
//     // 削除
//     itemDao.delete(item);
    }
}
Hibernate: 
    insert 
    into
        m_item
        (name, price, id) 
    values
        (?, ?, ?)

mysql> select * from m_item;
+----+--------+-------+
| id | name   | price |
+----+--------+-------+
|  1 | item01 |   100 |
+----+--------+-------+
1 row in set (0.00 sec)

・更新テスト

   // 更新
    item.setPrice(new BigDecimal(200));
    itemDao.update(item);
Hibernate: 
    update
        m_item 
    set
        name=?,
        price=? 
    where
        id=?

mysql> select * from m_item;
+----+--------+-------+
| id | name   | price |
+----+--------+-------+
|  1 | item01 |   200 |
+----+--------+-------+
1 row in set (0.00 sec)

・検索テスト

   // 検索
    Item item2 = itemDao.load(1);
    System.out.println(item2.getId());
    System.out.println(item2.getName());
    System.out.println(item2.getPrice());
Hibernate: 
    select
        item0_.id as id1_0_0_,
        item0_.name as name2_0_0_,
        item0_.price as price3_0_0_ 
    from
        m_item item0_ 
    where
        item0_.id=?
1
item01
200

・削除テスト

 // 削除
    itemDao.delete(item);
Hibernate: 
    select
        item_.id,
        item_.name as name2_0_,
        item_.price as price3_0_ 
    from
        m_item item_ 
    where
        item_.id=?
Hibernate: 
    delete 
    from
        m_item 
    where
        id=?


mysql> select * from m_item;
Empty set (0.00 sec)

※deleteの場合は、SQLがseleteとdelete2回発行されているね。

Spring4 - AOP

SpringのAOP

Annotation (XML定義も可能ね)

  • @AspectJ
  • @Before
  • @After
  • @AfterReturing
  • @AfterThrowing
  • @Aroud
  • @Pointcut

必要なjar

  • aopalliance.jar
  • aspectjrt.jar
  • aspectjweaver.jar

コード

<?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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <!-- bean検索 -->
    <context:component-scan base-package="app.aop"/>

    <!-- @AspectJ起動 -->
    <aop:aspectj-autoproxy/>

    <!-- xmlスキーマ使用しない場合 -->
    <!-- bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" -->
</beans>
package app.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(1) // 優先順位
public class FourAdviceTest {

    // pointcut定義
    @Pointcut("execution(* app.aop.*.*(..))")
    private void myPointCut(){}

    // pointcut実行前
    // @Before("execution(* app.aop.*.*(..))")
    @Before(value="myPointCut()")
    public void authority(JoinPoint jp) {
        System.out.println("Before advice.");
        System.out.println("目標オブジェクト" + jp.getTarget());
        System.out.println("目標メソッド : " + jp.getSignature().getName());
        System.out.println("目標メソッド引数 : " + Arrays.toString(jp.getArgs()));
    }

    // pointcut正常終了後
    @AfterReturning(pointcut = "execution(* app.aop.*.*(..))", returning = "ret")
    public void log(JoinPoint jp, String ret) {
        System.out.println("AfterReturning advice.");
        System.out.println("戻り値 : " + ret);
        System.out.println("目標オブジェクト" + jp.getTarget());
        System.out.println("目標メソッド : " + jp.getSignature().getName());
        System.out.println("目標メソッド引数 : " + Arrays.toString(jp.getArgs()));
    }

    // pointcut正常、異常終了後
    @After("execution(* app.aop.*.*(..))")
    public void release(JoinPoint jp) {
        System.out.println("After advice.");
        System.out.println("目標オブジェクト" + jp.getTarget());
        System.out.println("目標メソッド : " + jp.getSignature().getName());
        System.out.println("目標メソッド引数 : " + Arrays.toString(jp.getArgs()));
    }

    // pointcut前後、引数、戻り値修正可能
    // 強力な機能だな
    @Around("execution(* app.aop.*.*(..))")
    public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
        System.out.println("Around advice.");

        Object[] args = jp.getArgs();
        if (args != null && args.length > 0
                && args[0].getClass() == String.class) {
            // 引数を修正する
            args[0] = "AAA" + args[0];
        }
        // pointcutを実行する
        Object ret = jp.proceed(args);
        System.out.println("pointcut実行完了");
        //
        if (ret != null && ret instanceof Integer)
            ret = (Integer) ret * (Integer) ret;
        return ret;
    }
}
package app.aop;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component("helloWorld")
@Scope("singleton")
public class HelloWorld{

    public String hello(String str1, String str2) {
        return str1 + str2;
    }
}
package app.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAOP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("aop-beans.xml");

        HelloWorld h = (HelloWorld) context.getBean("helloWorld");
        h.hello("aaa", "bbb");
    }
}
Around advice.
Before advice.
目標オブジェクトapp.aop.HelloWorld@20d525
目標メソッド : hello
目標メソッド引数 : [AAAaaa, bbb]
pointcut実行完了
After advice.
目標オブジェクトapp.aop.HelloWorld@20d525
目標メソッド : hello
目標メソッド引数 : [AAAaaa, bbb]
AfterReturning advice.
戻り値 : AAAaaabbb
目標オブジェクトapp.aop.HelloWorld@20d525
目標メソッド : hello
目標メソッド引数 : [AAAaaa, bbb]

Spring4 - 零配置ファイル - Annotation利用

Springは「配置より規約」を採用してなく、Annotationを利用してどれをBeanとして扱うを決める。

SpringのBean定義用Annotaion

  • @Component
  • @Controller
  • @Service
  • @Repository

ライフサイクルAnnotation

  • @PostConstruct
  • @PreDestory

Spring3.0追加

  • @DependsOn : 他のbean強制初期化
  • @Lazy : 前もって初期化するか

Spring4.0

  • @Autowired

    • setter,通常メソッド、変数、コンストラクター修飾可能
    • setter修飾の場合、byTypeでDIする
    • @Autowired public void prepare(ClassA a, ClassB b)
    • byTypeの場合、複数見つかったらBeanCreateExceptionが発生する
    • private ClassA[] a; // ClassAのすべてのBeanをDI
  • @Qualifier

    • @Autowired @Qualifier("beanName") private ClassA classA; // ClassAのbeanNameのbean
    • public void setA(@Qualifier("beanName") ClassA classA) // 引数にも指定可能

サンプル

package app.annotationTest;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("singleton")
public class Japanese{

    private int age; // 年齢
    private String name; // 名前

    @Autowired
    @Qualifier("pen")
    private Pen pen;

    public Pen getPen() {
        return pen;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void info() {
        System.out.println("名前 : " + this.name);
        System.out.println("年齢 : " + this.age);
    }

    // 生成後
    @PostConstruct
    public void init() {
        System.out.println("初期化処理");
    }

    // 破棄前
    @PreDestroy
    public void destory() {
        System.out.println("破棄する前の処理");
    }
}
package app.annotationTest;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("singleton")
public class Pen {
    public void write() {
        System.out.println("文字を書きました");
    }
}
package app.annotationTest;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestComponent {
    public static void main(String[] args) {
        // ApplicationContext context = new ClassPathXmlApplicationContext("component-beans.xml");

        // Springコンテナー生成
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("component-beans.xml");

        // JVM終了時にコンテナーを破棄する
        context.registerShutdownHook();

        Japanese j = context.getBean(Japanese.class);
        j.info();
        j.getPen().write();
    }
}
<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 指定パッケージ配下のbeanを検索する -->
    <context:component-scan
        base-package="app.annotationTest"/>
</beans>
初期化処理
名前 : null
年齢 : 0
文字を書きました
破棄する前の処理

Spring4 - BeanFactoryPostProcessor - PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurerは、
propertiesファイルを読み取り、Springコンテナーのデータとして使える。

package app.propertyOverrideConfigurer;

public class Japanese{

    private int age; // 年齢
    private String name; // 名前

    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void info() {
        System.out.println("名前 : " + this.name);
        System.out.println("年齢 : " + this.age);
    }
}
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean class=
        "org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations">
            <list>
                <!-- propertieyファイル  -->
                <value>japanese.properties</value>
                <!-- 複数指定可能 -->
                <!--value>xxx.properties</value-->
            </list>
        </property>
    </bean>

    <!-- Bean定義 -->
    <!-- 属性を設定する必要がなく、propertyファイルから設定される -->
    <bean id="japanese" class="app.propertyOverrideConfigurer.Japanese" />
    
    <!-- XMLスキーマ利用 -->
    <!-- context-property-override location="classpath:japanese.properties"  -->
</beans>
package app.propertyOverrideConfigurer;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestPropertyOverrideConfigurer  {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("PorpertyOverrideConfigurerBean.xml");

        // Bean取得
        Japanese p = context.getBean("japanese", Japanese.class);
        p.info();
    }
}
名前 : SATO
年齢 : 20

Spring4 - BeanFactoryPostProcessor - PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurerは、
propertiesファイルを読み取り、Springコンテナーのデータとして使える。

package app.beanFactoryPostFrocessor;

public class Japanese{

    private int age; // 年齢
    private String name; // 名前

    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void info() {
        System.out.println("名前 : " + this.name);
        System.out.println("年齢 : " + this.age);
    }
}
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean class=
        "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <!-- propertieyファイル  -->
                <value>japanese.properties</value>
                <!-- 複数指定可能 -->
                <!--value>xxx.properties</value-->
            </list>
        </property>
    </bean>

    <!-- Bean定義 -->
    <bean id="japanese" class="app.beanFactoryPostFrocessor.Japanese"
        p:name="${name}"
        p:age="${age}" />
        
    <!-- XMLスキーマ利用 -->
    <context:property-placeholder loaction="classpath:japaense.properties" />
</beans>

japanese.properties

name=SATO
age=20
package app.beanFactoryPostFrocessor;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestPropertyPlaceholderConfigurer  {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("PorpertyPlaceholderConfigurerBean.xml");

        // Bean取得
        Japanese p = context.getBean("japanese", Japanese.class);
        p.info();
    }
}
名前 : SATO
年齢 : 20