zoukankan      html  css  js  c++  java
  • Hibernate+maven+eclipse 实现自动建表

    一、需求

    如题,当建好Model 时,不想自己手工建表,可以采取hibernate进行自动建表。下面将用一个小例子来说明如何将其实现。

    二、实现

    说明:1)这里用的是4.3.1.Final版本的hibernate,mysql-connector-java用的是5.1.26版本的;

            2)这里要手工新那一个数据库ssh,建库语句为:

    create database ssh;

    1.新建maven项目

      

    都填写好了,点击finish即可。

    2.项目架构图

     下面是maven默认的目录,如果没有main/java 和test/java那么自己手工建吧。

    3.代码

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.amos</groupId>
        <artifactId>spring_mvc_hibernate</artifactId>
        <packaging>war</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <name>spring_mvc_hibernate Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>4.3.1.Final</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.26</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>spring_mvc_hibernate</finalName>
        </build>
    </project>

    hibernate.cfg.xml

    <!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="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">root</property>
            <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/ssh?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull&amp;transformedBitIsBoolean=true
            </property>
            <property name="hibernate.hbm2ddl.auto">update</property>
            <property name="hibernate.cache.use_second_level_cache">false</property>
            <mapping class="com.amos.model.Person" />
        </session-factory>
    </hibernate-configuration>

     自动建表的关键是在<property name="hibernate.hbm2ddl.auto">update</property>,看hibernate的文档就发现还有其它几个选项:

     validate               加载hibernate时,验证创建数据库表结构
     create                  每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
     create-drop        加载hibernate时创建,退出是删除表结构
     update                 加载hibernate自动更新数据库结构,如果没有,那就新建数据结构。

    model中的Person.java

    package com.amos.model;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    import org.hibernate.annotations.GenericGenerator;
    @Entity
    @Table(name = "person2")
    public class Person {
        @Id
        @GenericGenerator(name = "generator", strategy = "increment")
        @GeneratedValue(generator = "generator", strategy = GenerationType.TABLE)
        @Column(unique = true, nullable = false)
        private Long id;
        @Column(name = "name", length = 50)
        private String name;
        @Column
        private Integer age;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }

    注:这里使用注解的方式,使用自增的方式,注意加粗的地方的配置。

    PersonDao.java

    package com.amos.dao;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.boot.registry.StandardServiceRegistry;
    import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
    import org.hibernate.cfg.Configuration;
    
    import com.amos.model.Person;
    
    /** 
    * @ClassName: PersonDao 
    * @Description: 用户dao
    * @author: amosli
    * @email:amosli@infomorrow.com
    * @date 2014年2月28日 下午6:01:19  
    */
    public class PersonDao {
        private static SessionFactory sessionFactory = null;
    
        public static void main(String[] args) {
        // SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
            createSessionFactory();
            Session session = sessionFactory.openSession();
            session.beginTransaction();
            Person person = new Person();
            person.setAge(18);
            person.setName("amos");
            session.save(person);
            session.getTransaction().commit();
            session.close();
            System.exit(0);
        }
    
        public static SessionFactory createSessionFactory() {
            Configuration cfg = new Configuration().configure();
            System.out.println("cfg.getProperties():" + cfg.getProperties());
            StandardServiceRegistry build = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
            sessionFactory = cfg.buildSessionFactory(build);
            return sessionFactory;
        }
    
    }

    注: 加粗的部分是重点,这里建议用未过时的就是新建一个ServiceRegistry。

    用 new Configuration().configure().buildSessionFactory()会提示:Deprecated. Use buildSessionFactory(ServiceRegistry) instead

     看源码,就会发现Configuration类中的buildSessionFactory()用的就是

    final ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
    .applySettings( properties )
    .build();

    这里模仿其用法,也用StandardServiceRegistryBuilder实现ServiceRegistry,经测试是没问题的。

     另,如果hibernate.cfg.xml自己更改为hibernate_test.xml那么应改怎么办?

     只需要在new Configuration().configure("hibernate_test.xml")即可,这样可以指定其去加载classpath下的.xml文件。

    4.效果

      

    5.遇到的问题

    Exception in thread "main" org.hibernate.AnnotationException: No identifier specified for entity: com.amos.model.Person
        at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:277)
        at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:224)
        at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:775)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3790)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3744)
        at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
        at com.amos.dao.PersonDao.main(PersonDao.java:11)

    出现个主要是因为在建model 时没有定义id为其主键,所以报错了,在其前面加上@Id即可。

    6.补充

    下面是: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">
    <!-- Generated by MyEclipse Hibernate Tools. -->
    <hibernate-configuration>
    
        <session-factory>
            <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
            <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="connection.url">${hibernate.credit.url}</property>
            <property name="connection.username">${hibernate.credit.username}</property>
            <property name="connection.password">${hibernate.credit.password}</property>
            <!--数据库连接池的大小 20 -->
            <!-- <property name="hibernate.connection.pool.size">1 </property> -->
            <property name="connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
            <!-- 最大连接数 -->
            <property name="hibernate.c3p0.max_size">50</property>
            <!-- 最小连接数 -->
            <property name="hibernate.c3p0.min_size">${hibernate.credit.min_size}</property>
            <!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 -->
            <property name="hibernate.c3p0.timeout">9000</property>
            <!-- 最多高速缓存 20 个预编译语句 不为0会报APPARENT DEADLOCK!!!死锁警告 -->
            <property name="hibernate.c3p0.max_statements">0</property>
            <!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
            <property name="hibernate.c3p0.acquire_increment">2</property>
            <!-- 每隔600秒检查连接池里的空闲连接 ,单位是秒 -->
            <property name="hibernate.c3p0.idle_test_period">180</property>
    
            <property name="hibernate.c3p0.automaticTestTable">Test</property>
    
            <!-- 在checkout一个connection时候,判断这个connection没有被使用的时间是否大于maxIdleTime,来决定是关闭它,还是被checkout -->
            <!-- <property name="maxIdleTime">1800</property> -->
    
            <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
            <property name="acquireRetryAttempts">30</property>
            <!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
            <property name="acquireRetryDelay">1000</property>
            <!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
            <property name="autoCommitOnClose">true</property>
    
            <!-- -jdbc.fetch_size是指Hibernate每次从数据库中取出并放到JDBC的Statement中的记录条数.Fetch 
                Size设的越大,读数据库的次数越少,速度越快, -->
            <!-- Fetch Size越小,读数据库的次数越多,速度越慢 -->
            <property name="jdbc.fetch_size">30 </property>
            <!--jdbc.batch_size是指Hibernate批量插入,删除和更新时每次操作的记录数。Batch Size越大,批量操作的向数据库发送Sql的次数越少,速度就越快,同样耗用内存就越大 -->
            <property name="jdbc.batch_size">30 </property>
            <!--jdbc.use_scrollable_resultset是否允许Hibernate用JDBC的可滚动的结果集。对分页的结果集。对分页时的设置非常有帮助 -->
            <property name="jdbc.use_scrollable_resultset">true </property>
            <!--connection.useUnicode连接数据库时是否使用Unicode编码 -->
            <property name="Connection.useUnicode">true </property>
            <!--connection.characterEncoding连接数据库时数据的传输字符集编码方式,最好设置为gbk,utf-8,用gb2312有的字符不全 -->
            <property name="connection.characterEncoding">utf-8 </property>
            <!-- 执行事务的方式 -->
            <property name="current_session_context_class">thread</property>
            <!-- <property name="current_session_context_class">jta</property> -->
            <!-- 事物隔离-防止查询出现缓存 Read Committed(读取提交内容) 1,2,4,8 -->
            <property name="hibernate.connection.isolation">2</property>
            <!-- 是否更新表 TODO 需要关闭! update false -->
            <property name="hibernate.hbm2ddl.auto">update</property>
            <property name="show_sql">false</property>
            <property name="format_sql">false</property>
            <mapping class="com.amos.model.Person" />
        </session-factory>
    </hibernate-configuration>

    test.properties

    hibernate.credit.url=jdbc:mysql://127.0.0.1:3306/juxinli_credit?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull&amp;transformedBitIsBoolean=true
    hibernate.credit.username=root
    hibernate.credit.password=root
    hibernate.credit.min_size=5

    在pom.xml 中 </dependencies>之后,</project>加上如下配置:

    </dependencies>
    
       <build>
            <finalName>hibernate</finalName>
            <defaultGoal>compile</defaultGoal>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.1</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                        <encoding>UTF-8</encoding>
                        <compilerArguments>
                            <extdirs>src/main/webapp/WEB-INF/lib</extdirs>
                        </compilerArguments>
                    </configuration>
                </plugin>
            </plugins>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
    
        </build>
    
        <profiles>
            <profile>
                <id>development</id>
                <activation>
                    <activeByDefault>true</activeByDefault>
                </activation>
                <build>
                    <filters>
                        <filter>src/main/resources/environment/test.properties</filter>
                    </filters>
                </build>
            </profile>
            <profile>
                <id>production</id>
                <build>
                    <filters>
                        <filter>src/main/resources/environment/production.properties</filter>
                    </filters>
                </build>
            </profile>
        </profiles></project>

     在使用maven打war包时:

    1)可以手动运行命令:

    mvn package -Ptest 

    这样表示的是打id为test的war包。

    2)也可以采用:项目名称,鼠标右键Run As--> Maven install 进行打包。

     7.本文源码

    https://github.com/amosli/hibernate_auto_create_table

  • 相关阅读:
    Dynamics 365/CRM 实体设计技巧
    Dynamics 365/CRM 保存之后触发onchange
    编写C#程序,计算去除最大值和最小值之后的平均值
    Dynamics 365 WebResourceUtility 工具更新
    No sandboxworker process or sandbox hosts are currently avaliable
    C#
    Dynamics CRM 365 and Azure Service Bus – Queue
    双for循环
    java switch 的练习
    java__if_else 的练习
  • 原文地址:https://www.cnblogs.com/amosli/p/3574171.html
Copyright © 2011-2022 走看看