对象关系映射(ORM)数据访问
一、Hibernate
从Spring Framework 5.0开始,Spring需要Hibernate ORM 4.3或更高版本来支持JPA,甚至需要Hibernate ORM5.0+来针对本机Hibernate会话API进行编程。请注意,Hibernate团队不再维护5.1之前的任何版本。
引入hibernate相关依赖
<!--hibernate需要的依赖包--> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.3.6.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>5.3.6.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.1.1.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> </dependencies>
创建数据源
db.properties
ps.datasource.driverClassName=com.mysql.jdbc.Driver ps.datasource.jdbcUrl=jdbc:mysql://localhost:3305/spring?useTimezone=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&tcpRcvBuf=1024000&useOldAliasMetadataBehavior=true&useSSL=false&rewriteBatchedStatements=true&useAffectedRows=true ps.datasource.username=root ps.datasource.password=123456
DbConfigBean.java
@Component @PropertySource("classpath:db.properties") public class DbConfigBean { @Value("${ps.datasource.driverClassName}") private String driverClassName; @Value("${ps.datasource.jdbcUrl}") private String jdbcUrl; @Value("${ps.datasource.username}") private String username; @Value("${ps.datasource.password}") private String password; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getJdbcUrl() { return jdbcUrl; } public void setJdbcUrl(String jdbcUrl) { this.jdbcUrl = jdbcUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
SpringConfig.java
/** * 创建默认的数据源对象 */ @Bean("defaultDataSource") public DataSource defaultDataSource(DbConfigBean configBean) { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClass(configBean.getDriverClassName()); ds.setJdbcUrl(configBean.getJdbcUrl()); ds.setUser(configBean.getUsername()); ds.setPassword(configBean.getPassword()); return ds; }
创建SessionFactory
/** * @MethodName sessionFactory * @Description 管理Hibernate的SessionFactory, 可能有多个,这里指定默认 */ @Bean("defaultSessionFactory") public SessionFactory defaultSessionFactory(DataSource defaultDataSource) throws IOException { LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); sessionFactoryBean.setDataSource(defaultDataSource); // 扫描@Entity注解的包 sessionFactoryBean.setPackagesToScan("com.hibernate.modules"); // 设置hibernate的扩展属性 Properties hibernateProperties = new Properties(); // 方言 hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect"); // 是否输出所有SQL语句到控制台 hibernateProperties.put("hibernate.show_sql", false); // 如果开启, Hibernate将收集有助于性能调节的统计数据. hibernateProperties.put("hibernate.generate_statistics", false); // 在SessionFactory创建时,自动检查数据库结构, 这里设置为update,一般也是设置该值 hibernateProperties.put("hibernate.hbm2ddl.auto", "update"); // 如果开启, Hibernate将在SQL中生成有助于调试的注释信息, 默认值为false. hibernateProperties.put("hibernate.use_sql_comments", false); sessionFactoryBean.setHibernateProperties(hibernateProperties); // 必须执行afterPropertiesSet,否则sessionFactoryBean.getObject()为null sessionFactoryBean.afterPropertiesSet(); return sessionFactoryBean.getObject(); }
创建事务管理器
/** * @MethodName defaultTransactionManager * @Description 默认的事务管理器 * @param defaultDataSource * @Return org.springframework.orm.hibernate5.HibernateTransactionManager */ @Bean("defaultTransactionManager") public PlatformTransactionManager defaultTransactionManager(DataSource defaultDataSource) throws IOException{ return new HibernateTransactionManager(defaultSessionFactory(defaultDataSource)); }
同时,在SpringConfig.java上添加@EnableTransactionManagement注解,开启事务支持。
代码示例
通用DAO
BaseDao.java
import java.io.Serializable; import java.util.List; import org.hibernate.criterion.DetachedCriteria; /** * Hibernate通用的持久层接口 */ public interface BaseDao<T> { /** * 保存 * @param entity * @return oid */ Serializable save(T entity); /** * 更新 * @param entity */ void update(T entity); /** * 保存或更新 * @param entity */ void saveOrUpdate(T entity); /** * 删除 * @param entity */ void delete(T entity); /** * 通过对象标识符获取对象 * @param oid * @return 标识符对应的对象,没找到则返回null */ T findById(Serializable oid); /** * 查找满足条件的总记录数 * @param detachedCriteria * @return */ Integer findRecordNumByPage(DetachedCriteria detachedCriteria); /** * 向分页对象中设置记录 * @param detachedCriteria 离线查询对象 * @param startIndex 开始索引 * @param pageSize 每页记录数 * @return */ List<T> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize); /** * 通过条件查询 * @param detachedCriteria * @return */ List<T> findByCriteria(DetachedCriteria detachedCriteria); /** * @MethodName findByHQL * @Description HQL查询 * @param hql * @param params * @Return java.util.List<T> */ List<T> findByHQL(String hql, Object... params); }
BaseDaoImpl.java
import com.hibernate.common.dao.BaseDao; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import javax.annotation.Resource; import javax.persistence.Query; import org.hibernate.SessionFactory; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Projections; import org.springframework.orm.hibernate5.support.HibernateDaoSupport; /** * Hibernate通用持久层接口实现类 */ public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> { // 存储泛型的实际参数 private Class<T> clazz; public BaseDaoImpl() { // 谁实现该类,这就是谁的类字节码 Class c = this.getClass(); // 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type Type type = c.getGenericSuperclass(); // 将类型强转为参数化类型 ParameterizedType pType = (ParameterizedType) type; // 获取该类的父类的所有实际类型参数,也就是泛型的实际参数 // 这里也就是获取BaseDaoImpl的实际类型参数 Type[] actualTypeArguments = pType.getActualTypeArguments(); // 将实际类型参数赋值给成员变量 clazz = (Class<T>) (actualTypeArguments[0]); } @Resource(name = "defaultSessionFactory") public void setMySessionFactory(SessionFactory sessionFactory) { super.setSessionFactory(sessionFactory); } @Override public Serializable save(T entity) { return this.getHibernateTemplate().save(entity); } @Override public void update(T entity) { this.getHibernateTemplate().update(entity); } @Override public void saveOrUpdate(T entity) { this.getHibernateTemplate().saveOrUpdate(entity); } @Override public void delete(T entity) { this.getHibernateTemplate().delete(entity); } @Override public T findById(Serializable oid) { return (T) this.getHibernateTemplate().get(this.clazz, oid); } @Override public Integer findRecordNumByPage(DetachedCriteria detachedCriteria) { // 设置记录数投影 detachedCriteria.setProjection(Projections.rowCount()); List<Long> list = (List<Long>) this.getHibernateTemplate().findByCriteria(detachedCriteria); // 将投影置为空 detachedCriteria.setProjection(null); if (list.size() > 0) { return list.get(0).intValue(); } return null; } @Override public List<T> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize) { // 指定hibernate在连接查询时,只封装成一个对象 detachedCriteria.setResultTransformer(DetachedCriteria.ROOT_ENTITY); return (List<T>) this.getHibernateTemplate().findByCriteria(detachedCriteria, startIndex, pageSize); } @Override public List<T> findByCriteria(DetachedCriteria detachedCriteria) { return (List<T>) this.getHibernateTemplate().findByCriteria(detachedCriteria); } @Override public List<T> findByHQL(String hql, Object... params) { Query query = this.getSessionFactory().getCurrentSession().createQuery(hql); for (int i = 0; params != null && i < params.length; i++) { query.setParameter(i, params); } return query.getResultList(); } }
实体类
/** * @Description 实体类注解 * @Entity 也有name属性,如果设置了,则在编写HQL时候必须使用该名称,否则则使用类名 */ @Entity @Table(name = "os_user") public class OsUserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_name", unique = false, nullable = false) private String userName; @Column(name = "age", nullable = true) private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
持久化DAO
OsUserDao.java
public interface OsUserDao extends BaseDao<OsUserEntity> { }
OsUserDaoImpl.java
@Repository public class OsUserDaoImpl extends BaseDaoImpl<OsUserEntity> implements OsUserDao { }
业务层service
OsUserService.java
public interface OsUserService { long saveUserEntity(OsUserEntity userEntity); }
OsUserServiceImpl.java
@Service public class OsUserServiceImpl implements OsUserService { @Autowired private OsUserDao osUserDao; @Transactional @Override public long saveUserEntity(OsUserEntity userEntity) { return ((Long)osUserDao.save(userEntity)).longValue(); } }
测试
@RunWith(SpringRunner.class) @WebAppConfiguration @ContextHierarchy({ @ContextConfiguration(classes = SpringConfig.class), @ContextConfiguration(classes = SpringMVCConfig.class) }) public class HibernateTest { @Autowired private OsUserService osUserService; @Test public void testHibernate(){ OsUserEntity userEntity = new OsUserEntity(); userEntity.setUserName(UUID.randomUUID().toString()); userEntity.setAge(29); long userId = osUserService.saveUserEntity(userEntity); System.out.println("生成的user_id = " + userId); } }
hibernate的相关知识
可选属性配置
属性名 | 用途 |
---|---|
hibernate.dialect | 一个Hibernate Dialect类名允许Hibernate针对特定的关系数据库生成优化的SQL.
取值 full.classname.of.Dialect |
hibernate.show_sql | 输出所有SQL语句到控制台. 有一个另外的选择是把org.hibernate.SQL这个log category设为debug。
eg. true | false |
hibernate.format_sql | 在log和console中打印出更漂亮的SQL。
取值 true | false |
hibernate.default_schema | 在生成的SQL中, 将给定的schema/tablespace附加于非全限定名的表名上.
取值 SCHEMA_NAME |
hibernate.default_catalog | 在生成的SQL中, 将给定的catalog附加于非全限定名的表名上.
取值 CATALOG_NAME |
hibernate.session_factory_name | SessionFactory创建后,将自动使用这个名字绑定到JNDI中.
取值 jndi/composite/name |
hibernate.max_fetch_depth | 为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度. 值为0意味着将关闭默认的外连接抓取.
取值 建议在0到3之间取值 |
hibernate.default_batch_fetch_size | 为Hibernate关联的批量抓取设置默认数量.
取值 建议的取值为4, 8, 和16 |
hibernate.default_entity_mode | 为由这个SessionFactory打开的所有Session指定默认的实体表现模式.
取值 dynamic-map, dom4j, pojo |
hibernate.order_updates | 强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。
取值 true | false |
hibernate.generate_statistics | 如果开启, Hibernate将收集有助于性能调节的统计数据.
取值 true | false |
hibernate.use_identifer_rollback | 如果开启, 在对象被删除时生成的标识属性将被重设为默认值.
取值 true | false |
hibernate.use_sql_comments | 如果开启, Hibernate将在SQL中生成有助于调试的注释信息, 默认值为false.
取值 true | false |
hibernate.hbm2ddl.auto |
在SessionFactory创建时,自动检查数据库结构,或者将数据库schema的DDL导出到数据库. 使用create-drop时,在显式关闭SessionFactory时,将drop掉数据库schema。 取值 validate | update | create | create-drop |
方言
RDBMS | 方言 |
---|---|
DB2 | org.hibernate.dialect.DB2Dialect |
PostgreSQL | org.hibernate.dialect.PostgreSQLDialect |
MySQL | org.hibernate.dialect.MySQLDialect |
MySQL with InnoDB | org.hibernate.dialect.MySQLInnoDBDialect |
MySQL with MyISAM | org.hibernate.dialect.MySQLMyISAMDialect |
Oracle (any version) | org.hibernate.dialect.OracleDialect |
Oracle 9i/10g | org.hibernate.dialect.Oracle9Dialect |
二、Mybatis
引入依赖包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.1.1.RELEASE</version> </dependency> <!-- mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <!-- mybatis/spring包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!-- 导入Mysql数据库链接jar包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <!-- C3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.5</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>mchange-commons-java</artifactId> <version>0.2.19</version> </dependency>
创建数据源
db.properties
ps.datasource.driverClassName=com.mysql.jdbc.Driver ps.datasource.jdbcUrl=jdbc:mysql://localhost:3305/spring?useTimezone=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&tcpRcvBuf=1024000&useOldAliasMetadataBehavior=true&useSSL=false&rewriteBatchedStatements=true&useAffectedRows=true ps.datasource.username=root ps.datasource.password=123456
DbConfigBean.java
@Component @PropertySource("classpath:db.properties") public class DbConfigBean { @Value("${ps.datasource.driverClassName}") private String driverClassName; @Value("${ps.datasource.jdbcUrl}") private String jdbcUrl; @Value("${ps.datasource.username}") private String username; @Value("${ps.datasource.password}") private String password; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getJdbcUrl() { return jdbcUrl; } public void setJdbcUrl(String jdbcUrl) { this.jdbcUrl = jdbcUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
SpringConfig.java
@Bean("defaultDataSource") public DataSource defaultDataSource(DbConfigBean configBean) throws Exception { ComboPooledDataSource pooledDataSource = new ComboPooledDataSource(); pooledDataSource.setDriverClass(configBean.getDriverClassName()); pooledDataSource.setJdbcUrl(configBean.getJdbcUrl()); pooledDataSource.setUser(configBean.getUsername()); pooledDataSource.setPassword(configBean.getPassword()); return pooledDataSource; }
配置SqlSessionFactoryBean
@Bean("defaultSessionFactoryBean") public SqlSessionFactoryBean defaultSessionFactoryBean(DataSource defaultDataSource){ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(defaultDataSource); // 扫描mybatis的xml映射文件 sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations()); return sqlSessionFactoryBean; } private Resource[] resolveMapperLocations() { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); List<String> mapperLocations = new ArrayList<>(); mapperLocations.add("classpath*:com/mybatis/modules/dao/*Mapper*.xml"); mapperLocations.add("classpath*:mapper/*Mapper*.xml"); List<Resource> resources = new ArrayList(); if (mapperLocations != null) { for (String mapperLocation : mapperLocations) { try { Resource[] mappers = resourceResolver.getResources(mapperLocation); resources.addAll(Arrays.asList(mappers)); } catch (IOException e) { // ignore } } } return resources.toArray(new Resource[resources.size()]); }
配置MapperScannerConfigurer
@Bean("defaultMapperScannerConfigurer") public MapperScannerConfigurer defaultMapperScannerConfigurer(){ MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer(); // DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 scannerConfigurer.setBasePackage("com.mybatis.modules.dao"); scannerConfigurer.setSqlSessionFactoryBeanName("defaultSessionFactoryBean"); return scannerConfigurer; }
配置事务管理器
/** * @MethodName defaultTransactionManager * @Description 默认的事务管理器 * @param defaultDataSource * @Return org.springframework.orm.hibernate5.HibernateTransactionManager */ @Bean("defaultTransactionManager") public PlatformTransactionManager defaultTransactionManager(DataSource defaultDataSource) throws IOException{ return new DataSourceTransactionManager(defaultDataSource); }
创建实体类
import java.io.Serializable; public class OsUserEntity implements Serializable { private static final long serialVersionUID = 7362722356438880253L; private Long id; private String userName; private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "OsUserEntity{" + "id=" + id + ", userName='" + userName + '\'' + ", age=" + age + '}'; } }
创建持久化接口
/** * 这里的@MapperScan就是上面所讲的Mapper扫描器中所需要的配置,会自动生成代理对象。 * 注意,接口中的方法名称要和对应的MyBatis映射文件中的语句的id值一样,因为生成的 * 动态代理,会根据这个匹配相应的Sql语句执行。另外就是方法的参数和返回值也需要注 * 意。接口中的方法如何定义,对应的MyBatis映射文件就应该进行相应的定义。 */ @MapperScan public interface OsUserMapper { List<OsUserEntity> findAllUser(); long saveUser(OsUserEntity userEntity); }
在resource/mapper目录下创建OsUserMapper.xml,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 为这个mapper指定一个唯一的namespace,namespace="com.mybatis.modules.dao.OsUserMapper"就是com.mybatis.modules.dao(包名)+OsUserMapper--> <mapper namespace="com.mybatis.modules.dao.OsUserMapper"> <select id="findAllUser" resultType="com.mybatis.modules.entity.OsUserEntity"> select id, user_name as userName, age from os_user </select> <insert id="saveUser" parameterType="com.mybatis.modules.entity.OsUserEntity" useGeneratedKeys="true"> <selectKey keyProperty="id" order="AFTER" resultType="long"> select LAST_INSERT_ID() </selectKey> insert into os_user(user_name, age) values (#{userName}, #{age}) </insert> </mapper>
创建服务类
OsUserService.java
public interface OsUserService { List<OsUserEntity> findAllUser(); long saveUserEntity(OsUserEntity userEntity); }
OsUserServiceImpl.java
@Service public class OsUserServiceImpl implements OsUserService { @Autowired private OsUserMapper osUserMapper; @Override public List<OsUserEntity> findAllUser() { return osUserMapper.findAllUser(); } @Transactional @Override public long saveUserEntity(OsUserEntity userEntity) { osUserMapper.saveUser(userEntity); return userEntity.getId(); } }
测试类
@RunWith(SpringRunner.class) @WebAppConfiguration @ContextHierarchy({ @ContextConfiguration(classes = SpringConfig.class), @ContextConfiguration(classes = SpringMVCConfig.class) }) public class MybatisTest { Logger logger = LoggerFactory.getLogger(MybatisTest.class); @Autowired private OsUserService osUserService; @Test public void testQuery(){ List<OsUserEntity> allUser = osUserService.findAllUser(); System.out.println("all user" + allUser.toString()); } @Test public void testSave(){ OsUserEntity entity = new OsUserEntity(); entity.setAge(22); entity.setUserName(UUID.randomUUID().toString()); long id = osUserService.saveUserEntity(entity); logger.debug("------------------"); System.out.println("user id = " + id); } }
扩展:还可以有以下两种方式实现:
1、采用接口org.apache.ibatis.session.SqlSession的实现类org.mybatis.spring.SqlSessionTemplate。mybatis中, sessionFactory可由SqlSessionFactoryBuilder.来创建。MyBatis-Spring 中,使用了SqlSessionFactoryBean来替代。
2、采用抽象类org.mybatis.spring.support.SqlSessionDaoSupport提供SqlSession。
三、JPA
JPA(Java Persistence API)本身是一种规范,它的本质是一种ORM规范(不是ORM框架,因为JPA并未提供ORM实现,只是制定了规范)因为JPA是一种规范,所以,只是提供了一些相关的接口,但是接口并不能直接使用,JPA底层需要某种JPA实现。
Hibernate 从3.2开始,就开始兼容JPA。JPA和Hibernate之间的关系,可以简单的理解为JPA是标准接口,Hibernate是实现,并不是对标关系。Hibernate属于遵循JPA规范的一种实现,但是JPA是Hibernate遵循的规范之一,Hibernate还有其他实现的规范。
Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。
这里我们就使用Spring Data JPA进行说明。
引入依赖
<!-- hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.3.6.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.3.6.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.6.Final</version> </dependency> <!-- spring data jpa, 内部依赖了spring其他的模块,版本也不一样,spring版本之间的差距还是比较大的。 所以这要选择版本时要特别注意,应与当前整体项目使用的版本相同或相近, 否则可能会报java.lang.NoSuchFieldError: IMPORT_BEAN_NAME_GENERATOR等一些奇奇怪怪的错误。 例如:我当前项目是spring 5.1.16.RELEASE, 我就选择了2.1.18.RELEASE --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>2.1.18.RELEASE</version> </dependency> <!-- C3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.5</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>mchange-commons-java</artifactId> <version>0.2.19</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>
数据源基础配置
db.properties
ps.datasource.driverClassName=com.mysql.jdbc.Driver ps.datasource.jdbcUrl=jdbc:mysql://localhost:3305/spring?useTimezone=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&tcpRcvBuf=1024000&useOldAliasMetadataBehavior=true&useSSL=false&rewriteBatchedStatements=true&useAffectedRows=true ps.datasource.username=root ps.datasource.password=123456
DbConfigBean.java
@Component @PropertySource("classpath:db.properties") public class DbConfigBean { @Value("${ps.datasource.driverClassName}") private String driverClassName; @Value("${ps.datasource.jdbcUrl}") private String jdbcUrl; @Value("${ps.datasource.username}") private String username; @Value("${ps.datasource.password}") private String password; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getJdbcUrl() { return jdbcUrl; } public void setJdbcUrl(String jdbcUrl) { this.jdbcUrl = jdbcUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
jpa相关的bean配置
// 如果需要多个entityManagerFactory,就定义多个拥有@Configuration的多个配置类,使用@EnableJpaRepositories指定相关属性即可 @Configuration @EnableJpaRepositories(basePackages = {"com.jpa.modules.dao"}, // 扫描dao transactionManagerRef = "defaultJpaTransactionManager", entityManagerFactoryRef = "defaultEntityManagerFactory") public class JpaBaseConfig { /** * @MethodName defaultDataSource * @Description 配置数据库连接池 */ @Bean("defaultDataSource") public DataSource defaultDataSource(DbConfigBean configBean) throws Exception { ComboPooledDataSource pooledDataSource = new ComboPooledDataSource(); pooledDataSource.setDriverClass(configBean.getDriverClassName()); pooledDataSource.setJdbcUrl(configBean.getJdbcUrl()); pooledDataSource.setUser(configBean.getUsername()); pooledDataSource.setPassword(configBean.getPassword()); return pooledDataSource; } /** * @MethodName defaultEntityManagerFactory * @Description 配置entityManagerFactory */ @Bean("defaultEntityManagerFactory") public EntityManagerFactory defaultEntityManagerFactory(DataSource defaultDataSource) { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(defaultDataSource); // 设置实体扫描包 entityManagerFactoryBean.setPackagesToScan("com.jpa.modules.entity"); entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); //JPA的供应商适配器 HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); jpaVendorAdapter.setGenerateDdl(true); jpaVendorAdapter.setDatabase(Database.MYSQL); jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect"); jpaVendorAdapter.setShowSql(true); entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter); entityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect()); entityManagerFactoryBean.afterPropertiesSet(); return entityManagerFactoryBean.getObject(); } /** * @MethodName defaultJpaTransactionManager * @Description Jpa 事务管理器 */ @Bean("defaultJpaTransactionManager") public JpaTransactionManager defaultJpaTransactionManager(EntityManagerFactory defaultEntityManagerFactory) { JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); jpaTransactionManager.setEntityManagerFactory(defaultEntityManagerFactory); return jpaTransactionManager; } }
注意:在SpringConfig.java中添加@Import(value = {JpaBaseConfig.class}),并开启注解支持@EnableTransactionManagement。
实体类
/** * @Description 实体类注解 * @Entity 也有name属性,如果设置了,则在编写JPQL时候必须使用该名称,否则则使用类名 */ @Entity @Table(name = "os_user") public class OsUserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_name", unique = false, nullable = false) private String userName; @Column(name = "age", nullable = true) private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
持久化接口
import com.jpa.modules.entity.OsUserEntity; import org.springframework.data.repository.PagingAndSortingRepository; /** * @Description 持久化接口 * 通过前面的配置可以看出 Spring 对 JPA 的支持已经非常强大,开发者无需过多关注 EntityManager 的创建、事务处理等 JPA 相关的处理 * *********************************************************************** * 在没用使用jpa支持的时候,我们的代码应该是这样的: * 1、UserDao 持久层接口 * 2、UserDaoImpl 持久层实现类 * 3、UserService 业务层接口 ...... 等等 * 每写一个实体类,都要衍生出5、6个类来对他进行操作,即使有了注解,我们可以依赖注入方式来拿到实现类。 * 但是通用的CRUD等操作却不免在每个实现类里声明,你又说,我可以定义一个父类,利用泛型反射原理就可以了, * 但那样你还需要为每个Dao声明自己的实现类来继承你的父类 。 * *********************************************************************** * Spring Data Jpa 为我们提供了一些通用的持久化接口,我们只需要声明接口,并继承这些已经封装好的接口即可。 * 1、Repository:是 Spring Data的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法。 * 2、CrudRepository:继承Repository,提供增删改查方法,可以直接调用。 * 3、PagingAndSortingRepository:继承CrudRepository,具有分页查询和排序功能(本类实例) * 4、JpaRepository:继承PagingAndSortingRepository,针对JPA技术提供的接口 * 5、JpaSpecificationExecutor:可以执行原生SQL查询 * 继承不同的接口,有两个不同的泛型参数,他们是该持久层操作的类对象和主键类型。 */ public interface UserDao extends PagingAndSortingRepository<OsUserEntity, Long> { }
测试
@RunWith(SpringRunner.class) @WebAppConfiguration @ContextHierarchy({ @ContextConfiguration(classes = SpringConfig.class), @ContextConfiguration(classes = SpringMVCConfig.class) }) public class SpringDataJpaTest { @Autowired private UserDao userDao; @Test public void testJpa(){ OsUserEntity entity = new OsUserEntity(); entity.setUserName(UUID.randomUUID().toString()); entity.setAge(27); userDao.save(entity); System.out.println("user_id = " + entity.getId()); Iterable<OsUserEntity> all = userDao.findAll(); Iterator<OsUserEntity> iterator = all.iterator(); while (iterator.hasNext()){ OsUserEntity userEntity = iterator.next(); System.out.println(userEntity.getUserName()); } } }