Spring笔记 - 访问数据库

1. 访问数据库

1.1 Spring的数据访问哲学

1.1.1 解耦数据访问层

- DAO皆为接口,面向接口编程

- DAO无关持久化技术

- Spring提供统一的数据访问异常体系,Spring提供的异常为非检查型异常,允许不捕获

1.1.2 数据访问模板化

- Spring将数据访问的相同部分抽象为模板,数据操作抽象为回调;前者包括连接管理、事务管理、资源管理和错误处理

- 模板例如JdbcTemplate


1.2 管理数据源

1.2.1 JNDI数据源

<!-- 在tomcat的server.xml中加入下面的配置,或在META-INF目录下面新建context.xml再加入下面的配置 -->
<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/demoDb" auth="Container" type="javax.sql.DataSource"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/demo"
        username="root"
        password="123"
        maxActive="50"
        maxIdle="30"
        maxWait="10000"/>
</Context>
<!-- 创建数据源,方法1 -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
    <property name="jndiName">  
        <value>java:comp/env/jdbc/demoDb</value>  
    </property>  
</bean> 
<!-- 创建数据源,方法2 -->
<beans>
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/demoDb"/>
</beans>
// JavaConfig方式
@Bean
public JndiObjectFactoryBean dataSource() {
   JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
   jndiObjectFB.setJndiName("jdbc/demoDb");
   jndiObjectFB.setResourceRef(true);
   jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
   return jndiObjectFB;
}

1.2.2 连接池

[参考]

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    <!-- 其他配置 ... -->
</bean>

1.2.3 JDBC数据源

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="com.mysql.jdbc.Driver"
    p:url="${jdbc.url}"
    p:username="${jdbc.username}"
    p:password="${jdbc.password}" />


1.3 JDBC模板

包括JdbcTemplate、NamedParameterJdbcTemplate,还有一个从Spring 3.1开始已经过时的SimpleJdbcTemplate

// 定义一个JdbcTemplate
@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
    return new NamedParameterJdbcTemplate(dataSource);
}
// 定义一个Repository
@Repository
public class UserRepository {
    private static final String sql = "select id, username from users where id=:id";
    
    @Resource("jdbcTemplate")
    NamedParameterJdbcTemplate jdbcTemplate; // 也可以使用JdbcOperations,JdbcTemplate实现了该接口,这样可以减少耦合
    
    public User findUser(int id) {
        Map params = new HashMap();
        params.put("id", id);
        return jdbcOperations.queryForObject(
            sql, new UserRowMapper(), params
        );
    }
    
    private static final class UserRowMapper implements RowMapper<Spitter> {
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            return new User(
                rs.getLong("id"),
                rs.getString("username"));
        }
    }
}

// 运用Java8 lamdas改写上面的代码
    public User findUser(int id) {
        // params ...
        return jdbcOperations.queryForObject(
            "sql语句", (rs, rowNum) -> {
                return new User(
                    rs.getLong("id"),
                    rs.getString("username"));
            }, params
        );
    }


1.4 集成ORM - Hibernate

- ORM可以提供延迟加载、预先抓取、级联、缓存、分布式缓存、生成SQL等功能

- Spring集成ORM,可以提供声明式事务、异常处理、资源管理等功能

1.4.1 HibernateTemplate

HibernaateTemplate会造成repository和Spring的耦合,现在推荐在repository里面注入HibernateSessionFactory,以此获得session

@Repository
public class UserDaoImpl implements UserDao {
    HibernaateTemplate hibernaateTemplate;
    
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernaateTemplate = new HibernaateTemplate(essionFactory);
    }
    
    public User findOne(int id) {
        return (User)this.hibernaateTemplate.get(User.class, id);
    }
}

1.4.2 Hibernate Session Factory

- Hibernate Session可以实现数据库数据的增删改查等功能

- Hibernate Session Factory可以开关并管理session

- Spring提供了org.springframework.orm.hibernate4.LocalSessionFactoryBean以获得Hibernate 4的session factory,与更早的版本不同,该版本可以同时支持xml和注解配置的Hibernate映射

// JavaConfig
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);
    // 支持xml配置的Hibernate映射
    factory.setMappingSource(new String[] {"User.hbm.xml"});
    // 支持注解配置的Hibernate映射
    // factory.setPackagesToScan(new String[] {"x.y.z.domain"});
    Properties props = new Properties();
    props.setProperty("dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
    factory.setHibernateProperties(props);
    return factory;
}

// 让平台相关的异常自动转换成Spring统一的非检查型异常,需结合@Repository注解
@Bean
public BeanPostProcessor persistenceTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
}

// DAO
@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    SessionFactory sessionFactory;
    
    public User findOne(int id) {
        return (User)sessionFactory.getCurrentSession().get(User.class, id);
    }
    
    public User findByUsername(String username) {
        return (User) sessionFactory.getCurrentSession()
            .createCriteria(User.class)
            .add(Restrictions.eq("username", username))
            .list().get(0);
    }
}
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mappingResources">
        <list>
            <value>x/y/z/domain/petclinic.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=${hibernate.dialect}
        </value>
    </property>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>


1.5 集成ORM - JPA

- JPA是Java EE 5的标准ORM接口,也是ejb3规范的一部分

- JPA是规范,要使用JPA,需要借助其实现,例如Hibernate、EclipseLink、TopLink、OpenJpa等

- Hibernate的核心之一是Session,JPA相对应的核心是Entity Manager

- Spring集成JPA的好处[参考]

  • Spring使得 JPA 配置变得更加灵活。JPA 规范要求,配置文件必须命名为 persistence.xml,并存在于类路径下的 META-INF 目录中。该文件通常包含了初始化 JPA 引擎所需的全部信息。Spring 提供的 LocalContainerEntityManagerFactoryBean 提供了非常灵活的配置,persistence.xml 中的信息都可以在此以属性注入的方式提供。

  • Spring 实现了部分在 EJB 容器环境下才具有的功能,比如对 @PersistenceContext、@PersistenceUnit 的容器注入支持。

  • Spring 将 EntityManager 的创建与销毁、事务管理等代码抽取出来,并由其统一管理,开发者不需要关心这些,DAO只需关注领域对象的操作,开发者无需关心事务管理和 EntityManager 创建、销毁。


你可能感兴趣的:(spring)