JavaEE 之 Spring Data JPA
1.事务
a.事务的关键属性(ACID)
①原子性(atomicity):事务的原子性确保动作要么全部完成,要么完全不起作用
②一致性(consistency):一旦所有事务动作完成,事务就被提交。也就是说要么都成功,要么都不成功
③隔离性(isolation):多个事物同时处理一个数据的时候,每个事物都应该与其他事务隔离开来,防止数据损坏
④持久性(durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。应该被持久化到数据库中
b.事务的传播行为
①REQUERED——PROPAGATION_REQUIRED
支持当前事务,如果没有事物则新建事物----最常用
②SUPPORTS
支持当前事务,如果没有事物,则以非事物的模式进行
③MANDATORY
支持当前事务,如果当前没有事物,则抛出异常
④REQUIRES-NEW
新建一个事物,如果当前存在事物,则将当前事务挂起
⑤NOT-SUPPORTED
以非事物的方式进行,如果当前有事物则将事物挂起
⑥NEVER
以非事物的方式进行,如果有事物则挂起
⑦NESTED
如果当前存在事物,则嵌套在事物内进行,如果当前没有事物,则和1的方式一样
c.事务的隔离特性
①ISOLATION_DEFAULT:使用数据库默认的隔离级别
②ISOLATION_READ_UNCOMMITTED:允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。 是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
③ISOLATION_READ_COMMITTED:允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
④ISOLATION_REPEATABLE_READ:对相同字段的多次读取结果一致,可导致幻读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
⑤ISOLATION_SERIALIZABLE:完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
d.事务针对的三大问题
①脏读:就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
②不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据---并且修改。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的
③幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样
2.Spring Data JPA
a.定义:通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
b.配置:
<!-- 配置自动扫描的包 --> <context:component-scan base-package="com.wode"> </context:component-scan> <!-- 配置数据源 --> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> </bean> <!-- 配置 JPA 的 EntityManagerFactory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"></property><!-- 添加数据源 --> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean> </property> <property name="packagesToScan" value="com.wode.entity"></property> <!-- hibernate 配置 --> <property name="jpaProperties"> <props> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <prop key="hibernate.hbm2ddl.auto">none</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <!-- 方言 hibernate 并不知道自己要使用哪种数据库 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="hibernate.cache.use_query_cache">true</prop> --> </props> </property> <!-- <property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property>--> </bean> <!-- 配置事务 纯事物 jpa事物 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <!-- 配置支持基于注解的事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 配置 SpringData --> <jpa:repositories base-package="com.wode.dao" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
c.书写Bean
@Entity @Table(name="users",catalog="dbcp") public class User implements Serializable{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) // @Column(name="user_id") private Integer userId; private String userName; private String userPwd; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } }
d.书写Dao接口
public interface UserDao extends JpaRepository<User, Integer>{ }
e.service层使用
userDao.save(user); //增 userDao.delete(userId); //删 List<User> users = userDao.findAll(); //查询所有 User user = userDao.findOne(userId); //根据Id查询
f.JPA命名规则
g.自定义JPA
@Query(value="select user_money from users where user_id=:id",nativeQuery=true) public double findUserMoneyByUserId(@Param("id") int id); @Modifying @Query(value="update users set user_money=:money where user_id=:id",nativeQuery=true) public void transMoney(@Param("money") double money,@Param("id") int id);