Shepard's Blog

Nothing is true everything is permitted


  • 首页

  • 标签

  • 分类

  • 归档

  • 公益404

  • 搜索

hibernate零散知识点整理

发表于 2015-05-13 | 分类于 Java , Hibernate |

c3p0配置

Hibernate整合C3P0实现连接池
hibernate与c3p0
hibernate中c3p0的配置

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
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">3</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">30</property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
<property name="autoCommitOnClose">false</property>
<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。
如果定义了这个参数那么属性preferredTestQuery将被忽略。
你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null-->
<property name="automaticTestTable">Test</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。
但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。
如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">false</property>
<!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>
<!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>
<!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
Default: null-->
<property name="factoryClassLocation">null</property>
<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文档原文)作者强烈建议不使用的一个属性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>
<!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">3</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">60</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">15</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。
但由于预缓存的statements属于单个connection而不是整个连接池。
所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">100</property>
<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection"></property>
<!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
通过多线程实现多个操作同时被执行。Default: 3-->
<property name="numHelperThreads">3</property>
<!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0
的数据源时。Default: null-->
<property name="overrideDefaultUser">root</property>
<!--与overrideDefaultUser参数对应使用的一个参数。Default: null-->
<property name="overrideDefaultPassword">password</property>
<!--密码。Default: null-->
<property name="password"></property>
<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>
<!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>
<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>
<!--用户名。Default: null-->
<property name="user">root</property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize" value="10" />
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="100" />
<!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="1800" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="1000" />
<property name="initialPoolSize" value="10" />
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="30" />

hibernate 乐观锁

Hibernate 乐观锁(Optimistic Locking)

hibernate基于数据版本(Version)记录机制实现。为数据增加一个版本标识,一般是通过为数据库表增加一个“version”字段来实现。 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据 版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

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
@Entity  
public class Conductor {
@Id
@GeneratedValue
private Integer id;

private String name;

@Version
private Long version;

//setter/getter
}

Session session1=openSession();
Session session2=openSession();
Conductor stu1=(Conductor)session1.createQuery("from Conductor as a where a.name='Bob'").uniqueResult();
Conductor stu2=(Conductor)session2.createQuery("from Conductor as a where a.name='Bob'").uniqueResult();

//这时候,两个版本号是相同的
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());

Transaction tx1=session1.beginTransaction();
stu1.setName("session1");
tx1.commit();
//这时候,两个版本号是不同的,其中一个的版本号递增了
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());

Transaction tx2=session2.beginTransaction();
stu2.setName("session2");

tx2.rollback();
session2.close();
session1.close();


注解实现联合主键

Hibernate注解映射联合主键的三种主要方式
hibernate注解方式实现复合主键

联合主键用Hibernate注解映射方式主要有三种:
第一、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,再将该类注解为@Embeddable,最后在主类中(该类不包含联合主键类中的字段)保存该联合主键类的一个引用,并生成set和get方法,并将该引用注解为@Id

1
2
3
4
5
6
7
8
9
@Entity  
@Table(name="JLEE01")
public class Jlee01 implements Serializable{
private String address ;
private int age ;
private String email ;
private String phone ;
@Id
private JleeKey01 jleeKey ;

主键类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Embeddable  
public class JleeKey01 implements Serializable{
private long id;
private String name;

//setter/getter

@Override
public boolean equals(Object o) {
if(o instanceof JleeKey01){
JleeKey01 key = (JleeKey01)o ;
if(this.id == key.getId() && this.name.equals(key.getName())){
return true ;
}
}
return false ;
}

@Override
public int hashCode() {
return this.name.hashCode();
}
}

第二、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,最后在主类中(该类不包含联合主键类中的字段)保存该联合主键类的一个引用,并生成set和get方法,并将该引用注解为@EmbeddedId

1
2
3
4
5
6
7
8
9
10
11
@Entity  
@Table(name="JLEE02")
public class Jlee02 {

private String address ;
private int age ;
private String email ;
private String phone ;
@EmbeddedId
private JleeKey02 jleeKey ;
// 主键类:JleeKey02.java为普通java类即可。

第三、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并要重写equals和hashcode.最后在主类中(该类包含联合主键类中的字段)将联合主键字段都注解为@Id,并在该类上方将上这样的注解:@IdClass(联合主键类.class)

1
2
3
4
5
6
7
8
9
10
11
@Entity  
@Table(name="JLEE03")
@IdClass(JleeKey03.class)
public class Jlee03 {
@Id
private long id ;
@Id
private String name ;

//setter/getter
}


hibernate.current_session_context_class

hibernate.current_session_context_class

从3.0.1版本开 始,Hibernate增加了SessionFactory.getCurrentSession()方法。一开始,它假定了采用JTA事务,JTA事务 定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的JTA TransactionManager实现稳定可用,不论是否被部署到一个J2EE容器中,大多数(假若不是所有的)应用程序都应该采用JTA事务管理。 基于这一点,采用JTA的上下文相关session可以满足你一切需要。

更好的是,从3.1开始,SessionFactory.getCurrentSession()的后台实现是可拔插的。因此,我们引入了新的扩展接口(org.hibernate.context.CurrentSessionContext)和新的配置参数(hibernate.current_session_context_class),以便对什么是“当前session”的范围和上下文(scope and context)的定义进行拔插。

请参阅org.hibernate.context.CurrentSessionContext接口的Javadoc,那里有关于它的契约的详细讨论。它定义了单一的方法,currentSession(),特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的三种实现。

org.hibernate.context.JTASessionContext - 当前session根据JTA来跟踪和界定。这和以前的仅支持JTA的方法是完全一样的。详情请参阅Javadoc。

org.hibernate.context.ThreadLocalSessionContext - 当前session通过当前执行的线程来跟踪和界定。详情也请参阅Javadoc。

org.hibernate.context.ManagedSessionContext - 当前session通过当前执行的线程来跟踪和界定。但是,你需要负责使用这个类的静态方法将Session实例绑定、或者取消绑定,它并不会打开(open)、flush或者关闭(close)任何Session。

前两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作每次请求一个session。Hibernate session的起始和终结由数据库事务的生存来控制。假若你在纯粹的 Java SE之上采用自行编写代码来管理事务,而不使用JTA,建议你使用Hibernate Transaction API来把底层事务实现从你的代码中隐藏掉。如果你使用JTA,请使用JTA借口来管理Transaction。如果你在支持CMT的EJB容器中执行代码,事务边界是声明式定义的,你不需要在代码中进行任何事务或session管理操作。

hibernate.current_session_context_class配置参数定义了应该采用哪个org.hibernate.context.CurrentSessionContext实现。注意,为了向下兼容,如果未配置此参数,但是存在org.hibernate.transaction.TransactionManagerLookup的配置,Hibernate会采用org.hibernate.context.JTASessionContext。一般而言,此参数的值指明了要使用的实现类的全名,但那三种内置的实现可以使用简写,即jta、thread和managed。

1、getCurrentSession()与openSession()的区别?

在 SessionFactory 启动的时候, Hibernate 会根据配置创建相应的 CurrentSessionContext ,在 getCurrentSession() 被调用的时候,实际被执行的方法是CurrentSessionContext.currentSession() 。在 currentSession() 执行时,如果当前 Session 为空,currentSession 会调用SessionFactory的openSession 。所以getCurrentSession() 对于 Java EE 来说是更好的获取 Session 的方法。

  • 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会
  • 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭

2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:

  • 如果使用的是本地事务(jdbc事务)

    1
    <property name="hibernate.current_session_context_class">thread</property>
  • 如果使用的是全局事务(jta事务)

    1
    <property name="hibernate.current_session_context_class">jta</property>
  • 如果使用的是session的管理机制(不太常用)

    1
    <property name="hibernate.current_session_context_class">managed</property>

LOB creation as createClob() method threw error

Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException

如果运行时出现下面提示的话:

1
2
3
INFO [pool-2-thread-1] - HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
INFO [pool-2-thread-1] - HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
INFO [pool-2-thread-1] - HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory

可以忽略也可以将驱动降级,例如Oracle,将class15替换成class14,Mysql,将mysql-connector-java-5.1.21.jar 替换成 mysql-connector-java-5.1.6.jar,以此类推


createSQLQuery is not valid without active transaction

如果你报createSQLQuery is not valid without active transaction,请看这里

使用 Hibernate 的大多数应用程序需要某种形式的“上下文相关的”会话,特定的会话在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种“上下文”下一个定义通常是困难的;不同的上下文对“当前”这个概念定义了不同的范围。
在 3.0 版本之前,使用 Hibernate 的程序要么采用自行编写的基于 ThreadLocal 的上下文会话,要么采用HibernateUtil 这样的辅助类,要么采用第三方框架(比如 Spring 或 Pico),它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关的会话。从 3.0.1 版本开始,Hibernate 增加了SessionFactory.getCurrentSession() 方法。一开始,它假定了采用 JTA 事务,JTA 事务定义了当前 session 的范围和上下文(scope 和 context)。因为有好几个独立的 JTA TransactionManager 实现稳定可用,不论是否被部署到一个 J2EE 容器中,大多数(假若不是所有的)应用程序都应该采用 JTA 事务管理。基于这一点,采用 JTA 的上下文相关的会话可以满足你一切需要。

hibernate 增加配置

1
<property name="hibernate.current_session_context_class">thread</property>

将getCurrentSession()返回的session绑定到当前运行线程中。

hibernate注解相关知识点

发表于 2015-05-13 | 分类于 Java , Hibernate |

注解标注的位置

来自 hibernate注解中JPA@标注的位置

对于JPA注解,最好放在方法前,而不要放在属性名前(Best Practice),因为属性一般都是私有的,放属性前面会破坏java的封装性,一般不要直接访问私有成员变量。此外最好还要保持field和get,set方法的一致。
如果写在属性前面,所有字段都要写在属性前;如果写在getter方法前面,所有字段都写在getter方法前面;必须保持一致

通过看官方文档了解到注解写在属性和方法上面的区别:

使用hibernate注解时,可以选择对类的属性或方法进行注解,根据注解位置不同,hibernate的访问类型分别为field或property。

EJB3规范要求在需要访问的元素上进行注解声明,例如:如果访问类型为 property就要在getter方法上进行注解声明,,如果访问类型为 field就要在字段上进行注解声明。

应该尽量避免混合使用这两种访问类型。(混用这两者造成程序报错,如value too long,但是很难找到问题所在) Hibernate根据@Id 或 @EmbeddedId的位置来判断访问类型。

若访问类型被标以”property”,则Hibernate会扫描getter方法的注解,若访问类型被标以”field”,则扫描字段的注解.否则,扫描标为@Id或@embeddedId的元素。

你可以覆盖某个属性(property)的访问类型,但是受注解的元素将不受影响: 例如一个具有field访问类型的实体,(我们)可以将某个字段标注为 @AccessType("property"), 则该字段的访问类型随之将成为property,但是其他字段上依然需要携带注解.


Hibernate JPA注解说明

来自
Hibernate JPA注解说明
Hibernate注解三个常见问题

@Entity(name=""): 必须,name为可选,对应数据库中一的个表
@Table(name="",catalog="",schema=""): 可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息

  • name:可选,表示表的名称.默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名
  • catalog:可选,表示Catalog名称,默认为Catalog("").
  • schema:可选,表示Schema名称,默认为Schema("").

@id: 必须,@id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键.置于getXxxx()前.
@GeneratedValue(strategy=GenerationType,generator=""): 可选

  • strategy:表示主键生成策略,有AUTO,INDENTITY,SEQUENCE 和 TABLE 4种,分别表示让ORM框架自动选择,根据数据库的Identity字段生成,根据数据库表的Sequence字段生成,以有根据一个额外的表生成主键,默认为AUTO
  • generator:表示主键生成器的名称,这个属性通常和ORM框架相关,例如,Hibernate可以指定uuid等主键生成方式.

@Basic(fetch=FetchType,optional=true): 可选,表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法,默认即为@Basic

  • fetch: 表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支紧急和延迟加载,默认为EAGER.
  • optional:表示该属性是否允许为null,默认为true

@Column: 可选,描述了数据库表中该字段的详细定义

  • name: 表示数据库表中该字段的名称,默认情形属性名称一致
  • nullable: 表示该字段是否允许为null,默认为true
  • unique: 表示该字段是否是唯一标识,默认为false
  • length: 表示该字段的大小,仅对String类型的字段有效
  • insertable: 表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中,默认为true
  • updateable: 表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true.对于一经创建就不可以更改的字段,该属性非常有用,如对于birthday字段.
  • columnDefinition: 表示该字段在数据库中的实际类型.通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或TEXT字段类型.

@Transient: 可选,表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
@ManyToOne(fetch=FetchType,cascade=CascadeType): 可选,表示一个多对一的映射,该注解标注的属性通常是数据库表的外键

  • optional: 是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true
  • fetch: 表示抓取策略,默认为FetchType.EAGER
  • cascade: 表示默认的级联操作策略,可以指定为ALL,PERSIST,MERGE,REFRESH和REMOVE中的若干组合,默认为无级联操作
  • targetEntity: 表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity.
    示例:
    1
    2
    3
    4
    5
    6
    7
    //订单Order和用户User是一个ManyToOne的关系
    //在Order类中定义
    @ManyToOne()
    @JoinColumn(name="USER")
    public User getUser() {
    return user;
    }

@JoinColumn: 可选,描述的不是一个简单字段,而是一个关联字段,例如.描述一个@ManyToOne的字段

  • name: 该字段的名称.由于@JoinColumn描述的是一个关联字段,如ManyToOne,则默认的名称由其关联的实体决定.

@OneToMany(fetch=FetchType,cascade=CascadeType): 可选,描述一个一对多的关联,该属性应该为集体类型,在数据库中并没有实际字段.

  • fetch: 表示抓取策略,默认为FetchType.LAZY,因为关联的多个对象通常不必从数据库预先读取到内存
  • cascade: 表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新或删除
    示例:
    1
    2
    3
    4
    @OneTyMany(cascade=ALL)
    public List getOrders() {
    return orders;
    }

@OneToOne(fetch=FetchType,cascade=CascadeType): 可选,描述一个一对一的关联

  • fetch: 表示抓取策略,默认为FetchType.LAZY
  • cascade: 表示级联操作策略

@ManyToMany: 可选,描述一个多对多的关联.多对多关联上是两个一对多关联,但是在ManyToMany描述中,中间表是由ORM框架自动处理

  • targetEntity: 表示多对多关联的另一个实体类的全名,例如:package.Book.class
  • mappedBy: 表示多对多关联的另一个实体类的对应集合属性名称
    示例:
    User实体表示用户,Book实体表示书籍,为了描述用户收藏的书籍,可以在User和Book之间建立ManyToMany关联
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Entity
    public class User {
    private List books;
    @ManyToMany(targetEntity=package.Book.class)
    public List getBooks() {
    return books;
    }
    public void setBooks(List books) {
    this.books=books;
    }
    }
    @Entity
    public class Book {
    private List users;
    @ManyToMany(targetEntity=package.Users.class, mappedBy="books")
    public List getUsers() {
    return users;
    }
    public void setUsers(List users) {
    this.users=users;
    }
    }

两个实体间相互关联的属性必须标记为@ManyToMany,并相互指定targetEntity属性,
需要注意的是,有且只有一个实体的@ManyToMany注解需要指定mappedBy属性,指向targetEntity的集合属性名称
利用ORM工具自动生成的表除了User和Book表外,还自动生成了一个User_Book表,用于实现多对多关联

@MappedSuperclass: 可选,可以将超类的JPA注解传递给子类,使子类能够继承超类的JPA注解
示例:

1
2
3
4
5
6
7
8
@MappedSuperclass
public class Employee() {}

@Entity
public class Engineer extends Employee {}

@Entity
public class Manager extends Employee {}

@Embedded: 可选,@Embedded将几个字段组合成一个类,并作为整个Entity的一个属性.
例如User包括id,name,city,street,zip属性.
我们希望city,street,zip属性映射为Address对象.这样,User对象将具有id,name和address这三个属性.
Address对象必须定义为@Embededable
示例:

1
2
3
4
5
6
7
@Embeddable
public class Address {city,street,zip}
@Entity
public class User {
@Embedded
public Address getAddress() {}
}


MySQL中Text, MeduimText, LongText在Hibernate中的设置

来自 MySQL中Text, MeduimText, LongText在Hibernate中的设置

1
2
3
4
5
6
7
@Lob(type = LobType.CLOB, fetch = FetchType.LAZY)
//Hibernate会对应到MySQL的MeduimText上去。MedumnText最大16777215字节
//如果length = 16777215则对应到LongText。LongText最大2147483647字节
@Column(length = 16777215)
public String getXXX(){
return xxx;
}

@Lob 通常与@Basic同时使用,提高访问速度。

1
2
3
4
5
6
@Lob 
@Basic(fetch = FetchType.LAZY)
@Column(name="DtaContent", columnDefinition="CLOB", nullable=true)
public String getDtaContent() {
return dtaContent;
}

如果提示为found text,excepted clob
改为columnDefinition="TEXT"就可以了。


hibernate lazy fetch

来自
hibernate lazy fetch
Hibernate检索策略之5.1类级别检索策略——Hibernate4究竟怎么玩

lazy是延迟加载,默认是延迟加载。
主要是为了系统的性能,当一张表引用到另外一张表时,如果不是立即需要另外一张表的内容,就可以采取延迟加载,直到要用到时才加载另外一张表。
fetch 和 lazy 主要是用来级联查询的,
而 cascade 和 inverse 主要是用来级联插入和修改的
fetch参数指定了关联对象抓取的方式是select查询还是join查询,
select方式时先查询返回要查询的主体对象(列表),再根据关联外键 id,
每一个对象发一个select查询,获取关联的对象,形成n+1次查 询;
而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。
如果你的关联对象是延迟加载的,它当然不会去查询关联对象。 另外,在hql查询中配置文件中设置的join方式是不起作用的(而在所有其他查询方式如get、criteria或再关联获取等等都是有效的),会使用 select方式,除非你在hql中指定join fetch某个关联对象。fetch策略用于定义 get/load一个对象时,如何获取非lazy的对象/集合。 这些参数在Query中无效。


Hibernate的cascade属性

来自
Hibernate的cascade属性 特别是 cascadeType.all的 作用
Hibernate基础之十:一对多关联的CRUD__@ManyToOne(cascade=(CascadeType.ALL))

JPA中的CascadeType.ALL并不等于{CascadeType.PESIST,CascadeType.REMOVE,CascadeType.MERGE,CascadeType.REFRESH}
在Hibernate中调用session.save() or session.update()并不能触发 {CascadeType.PESIST,CascadeType.REMOVE,CascadeType.MERGE,CascadeType.REFRESH} 的级联操作,而能触发CascadeType.ALL的级联。如不希望用CascadeType.ALL,需要使用Hibernate自身对 cascade的注解

1
@Cascade(value=org.hibernate.annotations.CascadeType.SAVE_UPDATE)


假定一个组里有n多用户,但是一个用户只对应一个用户组。

1.所以Group对于Users是“一对多”的关联关系@OneToMany,Users对于Group是“多对一”@ManyToOne
2.CRUD时候,希望是能从具体用户Users查到其对应的Group,反过来也能通过Group查到具体Users,所以是双向关联(所以要用mappedBy去除冗余信息)

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
@Entity  
@Table(name="t_Group")//指定一个表名
public class Group
{
private int id;
private String name;
private Set<Users> users = new HashSet<Users>();

@Id
@GeneratedValue//主键用自增序列
public int getId() {
return id;
}
@OneToMany(mappedBy="group",cascade=(CascadeType.ALL))//以“多”一方为主导管理,级联用ALL
public Set<Users> getUsers() {
return users;
}
//setter
}

@Entity
@Table(name="t_Users")
public class Users
{
private int id;
private String name;
private Group group;

@Id
@GeneratedValue
public int getId() {
return id;
}
@ManyToOne(fetch=FetchType.LAZY,cascade=(CascadeType.ALL))//解决1+N,级联用ALL
@JoinColumn(name="groupId")//指定外键名称,不指定的默认值是group_Id
public Group getGroup() {
return group;
}
//setter
|

C增
cascade:级联,只影响cud,不影响r(all全都级联,persist存储时级联,remove删除时级联)
如果没有设置cascade,默认需要save(Group)和save(users),两个都要存,设置级联之后,只存一个就行了
级联依赖于这句:@ManyToOne(cascade=(CascadeType.ALL))//需要依赖于其他的东西时候
设置好正反向之后,多个有级联关系的对象就一起被保存了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Users u1 = new Users();  
Users u2 = new Users();
u1.setName("u1");
u2.setName("u2");
//u1和u2的id自增

Group g = new Group();
g.setName("g1");
//g的id自增

g.getUsers().add(u1);//正向
g.getUsers().add(u2);

u1.setGroup(g);//反向
u2.setGroup(g);//不然u1和u2中的group信息为空

session.save(g);//因为设置级联,所以存储g时候也把u1和u2存上了。
//不设置级联的话,还要存储u1和u2

R查
默认会这样处理(平时管用的思路也是这样):
1.取“多”的时候,把“一”取出来
2.取“一”时,不取“多”的,用到时候再去取(看user信息时候一般看组名,看group时候user信息太多不必看)
fetch管读取,cascade管增删改
@OneToMany(mappedBy="group",cascade=(CascadeType.ALL),fetch=FetchType.EAGER)
@OneToMany默认的是LAZY,@ManyToOne默认是EAGER

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
Users u = (Users)session.get(Users.class,11);//取id为11号的u  
//hibernate产生的语句里也把group拿出来了:group1_.id as id0_0_,和group1_.name as name0_0_

Hibernate:
select
users0_.id as id1_1_,
users0_.groupId as groupId1_1_,
users0_.name as name1_1_,
group1_.id as id0_0_,
group1_.name as name0_0_
from
t_Users users0_
left outer join
t_Group group1_
on users0_.groupId=group1_.id
where
users0_.id=?

//只取出Group的话,不会去查询里边的user
Group group = (Group)session.get(Group.class,11);

Hibernate:
select
group0_.id as id0_0_,
group0_.name as name0_0_
from
t_Group group0_
where
group0_.id=?

U更新
注意:fetch影响两者读取顺序(两边都设成EAGER要多取出一次)
@OneToMany,@ManyToOne都写cascade=(CascadeType.ALL)
update时候自动关联更新

1
2
3
4
//因为cascade=(CascadeType.ALL),所以自动关联更新  
Users u = (Users)session.load(Users.class,11);//取id为11号的u
u.setName("u250");
u.getGroup().setName("gp01");

D删
删多:实测只删掉目的项目,不关联其他
先load(就是select)一下,确认有之后,再删

1
2
3
4
5
6
7
Users u1 = new Users();  
u1.setId(18);
u1.setGroup(null);//严谨起见,应该先让俩表脱离关联
session.delete(u1);

//hql删除
s.createQuery("delete from User u where u.id = 1").executeUpdate();//User是类名

jQuery 部分插件整理

发表于 2015-05-12 | 分类于 JavaScript , jQuery |

收集一些jQuery插件使用过程中碰到的问题解决方法。

阅读全文 »

jQuery零散知识点整理

发表于 2015-05-11 | 分类于 JavaScript , jQuery |

收集一些平时使用jQuery碰到的问题解决方法及相关知识点。

阅读全文 »

JavaScript 相关知识点整理

发表于 2015-05-11 | 分类于 JavaScript |

JavaScript是一门魔性语音,因此收集了不少使用过程中碰到的问题解决方法及相关知识点。

阅读全文 »

html标签与css样式表

发表于 2015-05-10 | 分类于 web , css |

html实线边框的表格样式定义

html实线边框的表格样式定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
table
{
border-collapse:collapse;
border-left:solid 1 #000000; border-top:solid 1 #000000;
padding:5px;
}


th
{
border-right:solid 1 #000000;
border-bottom:solid 1 #000000;
background-color: Silver;
}

td
{
font:normal;
border-right:solid 1 #000000;
border-bottom:solid 1 #000000;
background-color: transparent;
}

表格奇偶行不同颜色

来自 纯CSS table 表格奇偶行不同颜色实现

1
2
3
.table-striped tbody tr:nth-child(odd) td {
background-color: Red;
}
1
2
<table class="table-striped">
</table>

CSS发光边框文本框效果

来自 CSS发光边框文本框效果

1
2
3
4
5
6
7
8
9
input[type=text]:focus,input[type=password]:focus,textarea:focus{
transition:border linear .2s,box-shadow linear .5s;
-moz-transition:border linear .2s,-moz-box-shadow linear .5s;
-webkit-transition:border linear .2s,-webkit-box-shadow linear .5s;
outline:none;border-color:rgba(241,39,242,.75);
box-shadow:0 0 8px rgba(241,39,232,.5);
-moz-box-shadow:0 0 8px rgba(241,39,232,.5);
-webkit-box-shadow:0 0 8px rgba(241,39,232,3);
}

其中的RGB色彩可以根据个人口味进行改变


html table td边框效果

html table td边框效果

同时用样式表为 table、td 指定了边框后,可能会发生重叠,这取决于 border-collapse

1
2
3
4
5
6
7
8
<table style="border:1px solid red;border-collapse:collapse;">
<tr>
<td style="border:1px solid blue;">&nbsp;</td>
<td style="border:1px solid blue;">&nbsp;</td>
<td style="border:1px solid blue;">&nbsp;</td>
<td style="border:1px solid blue;">&nbsp;</td>
</tr>
</table>

在发生重叠时,Firefox 是用 td 覆盖 table 的,而 IE 是用 table 覆盖 td 的

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
<table border="1" bordercolor="#FF9966" >
<tr>
<td width="102" style="border-right-style:none">隐藏右边框</td>
<td width="119" style="border-left-style:none">隐藏左边框</td>
</tr>
<tr>
<td style="border-top-style:none">隐藏上边框</td>
<td style="border-bottom-style:none">隐藏下边框</td>
</tr>
</table>

<table>
<tr>
<td style="border-right:#cccccc solid 1px;">显示右边框</td>
<td style="border-left:#cccccc solid 1px;">显示左边框</td>
<td style="border-top:#cccccc solid 1px;">显示上边框</td>
<td style="border-bottom:#cccccc solid 1px;">显示下边框</td>
</tr>
</table>

<table>
<tr>
<td style="border-right : thin dashed blue;">右边框显示细虚线</td>
<td style="border-bottom: thick dashed yellow;">左边框显示粗虚线</td>
<td style="border-top: double green;">上边框显示两条线</td>
<td style="border-left: dotted red;">下边框显示点</td>
</tr>
</table>


实现Parallax效果

Creating Scrolling Parallax Effects with CSS

之前浏览网页,发现一个挺有意思的效果,就是滚动了文章之后,他间隔的背景图片会不断的变化。当时觉得很新奇,就想着该怎么实现,然后用蹩脚的英文在谷歌上输入了几个单词,结果想不到还真的查到了。原来这种效果叫Parallax。实现起来也十分简单:

1
2
3
4
5
6
7
8
9
10
.parallax {
height: 70vh;
background-position: center center;
background-repeat: no-repeat;
background-attachment: fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}

最核心的就是background-attachment: fixed这句。然后再弄一张背景图片:

1
2
3
.parallax-1 {
background-image: url("...");
}

最后直接使用样式即可:

1
2
3
<section class="parallax parallax-1">
//...
</section>

html表单

发表于 2015-05-09 | 分类于 web , html |

禁止文本框的记忆性输入

禁止文本框的记忆性输入 ,input ,textbox

设置表单属性AUTOCOMPLETE为OFF

1
<form method="post" AUTOCOMPLETE="OFF">

设置单个输入框

1
<input type="text" AUTOCOMPLETE="OFF">

如果要禁止文本框使用输入法,可以把在它的样式中添加 ime-mode : disabled 即可,但是这样并不能禁止输入汉字,因为用户还是可以通过复制粘贴输入汉字的

1
<input type="text" style="ime-mode: disabled;">


提交表单后清空输入框内容

如何使表单提交后,清空表单中文本框的内容

提交按钮的onClick方法指定表单提交之后执行reset方法

1
2
3
4
<form id="form1" method="post">
<input type="text" id="text1">
<input type="button" value="Submit" onClick="form1.submit();form1.reset();">
</form>


让select下拉列表只读

如何让select下拉选择只读
如何把select选项给只读,让他不可选,但数据还是保存在下拉表中

1
2
3
4
5
6
7
<select onchange="selectedIndex=this.defaultChecked">
<option>1</option>
<option>2</option>
<option>3</option>
</select>

<select onfocus="this.blur()" onmouseover="this.setCapture()" onmouseout="this.releaseCapture()">

强制页面图片刷新

不刷新页面,如何强制图片刷新?

只要保证每次src的字符串不同就会重取

1
2
3
4
var date=new Date();
img1.src=图片地址+"?"+date.toLocaleString();
//or
img1.src=img1.src + "?" + (new Date().getTime())


用get方法丢失参数

用get方法丢失参数啦 请指教

如果提交的表单action中跟的参数与表单中的某个参数重名,则会造成参数丢失的情况,这时设置表单的method方法为post即可。或者写入隐藏域中,即使用<input type="hidden">


表单中的button类型问题

button会自动提交表单吗

如果在表单中使用了button标签,一定要为其指定type类型,如果不指定,IE默认其为button类型,而FF,Chrome等浏览器则认定其默认类型为Submit,因此点击button会提交表单。为了预防表单提交,可以设置表单的onSubmit方法返回false,然后再指定button的点击事件为提交方法:

1
2
3
<form action="" method="post" id="form1" onSubmit="return false">
<button type="button" onClick="submitForm()">
</form>

Struts2 文件上传下载

发表于 2015-05-09 | 分类于 Java , Struts2 |

使用Struts2实现文件上传与下载的功能。

阅读全文 »

Struts2零散知识点整理

发表于 2015-05-09 | 分类于 Java , Struts2 |

平时使用Struts2碰到的一些问题的解决方法。

阅读全文 »

MongoDB简单使用

发表于 2015-05-07 | 分类于 Database , MongoDB |

MongoDB增删查改

8天学通MongoDB——第二天 细说增删查改
mongodb_修改器($inc/$set/$unset/$push/$pop/upsert)
MongoDB基本命令用

insert操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//创建一个集合
db.createCollection("students");
var student = {"sno":1,"sname":"s1",age:12,"course":["chinese","math"]};
db.students.insert(student);

student.sno=2;
student.sname="s2";
student.age=14;
student.course=["math","english"];

db.students.insert(student);

//查询所有记录
db.students.find();

这里已经成功的写入了2条记录

如果需要批量插入,可以使用for循环语句来插入

1
2
3
4
5
6
7
8
9
//删除所有记录
db.students.remove("");

for(var i=1; i<=10; i++){
var student = {"sno":i,"sname":"s"+i,age:i,"course":["chinese","math"]};
db.students.insert(student);
}

db.students.find();

save()函数可以添加数据,添加的列随意指定,如果调用了集合中默认的主键_id,则会进行更新操作

1
2
3
4
5
6
//插入新数据
db.students.save({sno:123,sname:"ss",age:15});
//更新数据
var student = db.students.findOne();
student.age = 11;
db.students.save(student);


select操作

操作符对应 >为$gt,>=为$gte,<为$lt,<=为$lte,!=为$ne
关系连接符对应 or为$or, in为$in, not in为$nin

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
//默认每页显示20条记录,如果需要下一页使用it命令
db.studens.find();
select * from students

db.students.find({"age":1,"sname":"s1"});
select * from students where age = 1 and sname = "s1"

db.students.find({"sno":{$gt:5}, "course": {$in:["math"] } });
select * from students where sno > 5 and course in ("math")

db.students.find({$or: [{"sname":"s2"},{"age":5}]});
select * from students where sname = "s2" or age = 5

//查询指定属性
db.students.find({},{sname:1});
select sname from students
//sname也可以用true或false,当用ture的情况下和sname:1效果一样,
//如果用false就是排除sname,显示sname以外的列信息

//通过正则表达式实现模糊查询
db.students.find({"sname":/6/},{age:1})
select age from students where sname like '%6%'
db.students.find({"sname":/^s/,"sname":/5$/});
select * from students where sname like 's%' and sname like '%s'

//使用where方法来实现条件查询
db.students.find({$where:function(){return this.sno==7 || this.age==8 }});
select * from students where sno = 7 or age = 8

//排序,1为升序,-1为降序
db.students.find().sort({sno:-1});

//limit用于查询限定数之前的记录,skip用于查询限定数之后的记录
//两者组合可以用于分页,limit是pageSize,skip为页数*pageSize
db.students.find().limit(10).skip(5);

//查询第一条记录,可以跟条件查询
db.students.findOne();

//统计行数
db.students.count();
select count(*) from students
db.students.find({sno: {$exists: true}}).count();
select count(sno) from students
db.students.count({age:1});
select count age from students where age = 1;

//过滤重复数据
db.students.distinct("age");
select distinct age from students;

group操作

group主要的参数:
key: 需要分组的属性
initial: 每组都分享一个”初始化函数“,特别注意:是每一组,比如这个的age=20的value的list分享一个?
$reduce: 这个函数的第一个参数是当前的文档对象,第二个参数是上一次function操作的累计对象,第一次为initial中的{“students”:[]}。有多少个文档, $reduce就会调用多少次initial函数,age=22同样也分享一个initial函数
condition: 过滤条件
finalize: 这是个函数,每一组文档执行完后,多会触发此方法,那么在每组集合里面加上count也就是它的活了

1
2
3
4
5
6
7
8
9
10
11
db.students.group({
"key": {"age":true},
"initial": {"students":[]},
"$reduce": function(cur,prev){
prev.students.push(cur.sname);
},
"condition": {"age":{$gte:10}},
"finalize": function(out){
out.count = out.students.length;
}
});

执行的部分结果为:

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
[
{
"age" : 11,
"students" : [
"s1",
"s2"
],
"count" : 2
},
{
"age" : 12,
"students" : [
"s5",
"s3",
"s4"
],
"count" : 3
},
{
"age" : 14,
"students" : [
"s9",
"s10"
],
"count" : 2
},
{
"age" : 15,
"students" : [
"ss"
],
"count" : 1
}
]


Map-Reduce操作

官网示例

mapReduce其实是一种编程模型,用在分布式计算中,其中有一个map函数,这个称为映射函数,里面会调用emit(key,value),集合会按照你指定的key进行映射分组。
reduce函数为简化函数,会对map分组后的数据进行分组简化,注意:在reduce(key,value)中的key就是emit中的key,vlaue为emit分组后的emit(value)的集合,这里也就是很多{“count”:1}的数组
mapReduce则为最后的执行函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
db.students.mapReduce(
//map
function(){
emit(this.age, {count:1});
},
//reduce
function(key, value){
var result = {count: 0};
for(var i=0; i<value.length; i++){
result.count += value[i].count;
}
return result;
},
{
"query": {"sname":/^s/},
"out": "collection"
}
);

db.collection.find();

执行结果为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"result" : "collection", //存放的集合名
"timeMillis" : 514,
"counts" : {
"input" : 11, //传入文档的个数
"emit" : 11, //此函数被调用的次数
"reduce" : 3, //此函数被调用的次数?
"output" : 7 //最后返回文档的个数
},
"ok" : 1
}
> db.collection.find();
{ "_id" : 6, "value" : { "count" : 1 } }
{ "_id" : 7, "value" : { "count" : 1 } }
{ "_id" : 8, "value" : { "count" : 1 } }
{ "_id" : 11, "value" : { "count" : 2 } }
{ "_id" : 12, "value" : { "count" : 3 } }
{ "_id" : 14, "value" : { "count" : 2 } }
{ "_id" : 15, "value" : { "count" : 1 } }


游标查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var cursor = db.students.find();
//循环输出完毕,游标自动销毁,再次输入cursor则为空
while(cursor.hasNext()){
//输出json格式
printjson(cursor.next());
}

//使用forEach进行迭代
var cursor = db.students.find().sort({"age":-1}).limit(10).skip(5);
cursor.forEach(function(x){
print(x.sname);
});

//通过数组形式来访问游标数据
var cursor = db.students.find();
cursor[3];

//将游标转换成数组
var arr = db.students.find().toArray();
print(arr.length);

索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建索引
db.students.ensureIndex({sname:1,age:-1});

//唯一索引
db.students.ensureIndex({sname:1,{"unique":true}});

//查看当前集合的索引
db.students.getIndexes();

//查看所有索引记录大小
db.students.totalIndexSize();

//读取当前集合的所有index信息
db.students.reIndex();

//删除指定索引
db.students.dropIndex("sname_1_age_-1");

//删除所有索引
db.students.dropIndexes();

update操作

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
//$set即可对指定属性进行修改
db.students.update({sno:2},{$set:{age:11}});
update students set age=11 where sno=2;
//如果属性不存在则会创建该属性
db.students.update({sno:2},{$set:{teacher:"t2"}});

//$unset用来删除指定属性
db.students.update({sno:2},{$unset:{teacher:1}});

//$inc可以对数字型属性进行加法操作
db.students.update({sno:2},{$inc: {age: -9}});
update students set age=age-9 where sno=2;

//$push向文档的某个数组类型的键添加一个数组元素,
//不过滤重复的数据。添加时键存在,要求键值类型必须是数组;
//键不存在,则创建数组类型的键
db.students.update({sno:2},{$push: {course:"english"}});

//$addToSet可以避免插入重复的数据
db.students.update({sno:3},{$addToSet: {course:"english"}});
db.students.update({sno:2},{$addToSet: {course:"english"}});

//$pop类似栈的pop操作,可以从数组头部(-1),尾部(1|0)来取出元素,即从数组中删除元素
db.students.update({sno:2},{$pop: {course:1}});

//$pull从数组中删除指定元素
db.students.update({sno:3},{$pull:{course:"math"}});

//使用$或者数组下标可以定位到数组元素进行修改
db.students.update({sno:2},{$set:{"course.0":"chinese"}});

//upsert是insert or update的结合体,有则更新,无则新增,
//只要指定update的第三个参数为true即可
//update还有第四个参数,如果指定true,如果匹配多条则全部更新,默认只更新第一条
db.students.update({sno:4},{$set:{teacher:"t5"}},true);

其他操作

explain函数可以用来性能分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> db.students.find().explain();
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 11,
"nscannedObjects" : 11,
"nscanned" : 11,
"nscannedObjectsAllPlans" : 11,
"nscannedAllPlans" : 11,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"server" : "Ezio-Hu:27017",
"filterSet" : false
}

部分参数说明
cursor: BasicCursor这里的查找采用的是“表扫描”,也就是顺序查找
nscanned: 数据库浏览的文档数目
n: 最终返回的文档数
millis: 查询耗时

tojson: 将一个对象转换成json格式的对象

1
tojson(new Object('student'))

printjson: 将获取的对象输出json格式

1…3456
Shepard

Shepard

59 日志
25 分类
67 标签
GitHub
© 2015 — 2020 Shepard
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.4