談談Spring-Data的那些事兒

咱們在進行事務處理每每須要和數據庫進行交互,這其中有關係型數據庫(MySql,Sql Server,Oracle)或者是非關係型數據庫(Redis,Hadhoop),常見的操縱數據庫的方式就有JDBC和Spring JdbcTemplate,而這兩種處理方式其實很繁瑣並且代碼複用率也比較低。另外使用這這種方式進行實際開發時效率也比較低,今天咱們使用Spring Data進行開發。在進行開發以前咱們首先介紹一下什麼是Spring-Data,以及如何使用JDBC和Spring JDBCTemplate方式進行經常使用的CRUD功能的開發。

SpringData相關概念:

SpringData是Spring基於ORM框架、JPA規範封裝的一套JPA應用框架,它提供了包括增刪改查在內的經常使用功能,且易於擴展,可以使開發者用極簡的代碼實現對數據庫的訪問和操做。

什麼是JPA呢?

JPA全稱Java Persistence API,是sun提出的一個對象持久化規範,各JavaEE應用服務器自主選擇具體實現。JPA僅僅只是一個規範,而不是產品;使用JPA自己是不能作到持久化的。因此,JPA只是一系列定義好的持久化操做的接口,在系統中使用時,須要真正的實現者。

JPA的設計者是Hibernate框架的做者,所以Hibernate EntityManager做爲Jboss服務器中JPA的默認實現;Oracle的Weblogic使用EclipseLink(之前叫TopLink)做爲默認的JPA實現;IBM的Websphere和Sun的Glassfish默認使用OpenJPA(Apache的一個開源項目)做爲其默認的JPA實現。
JPA的底層實現是一些流行的開源ORM(對象關係映射)框架,所以JPA其實也就是java實體對象和關係型數據庫創建起映射關係,經過面向對象編程的思想操做關係型數據庫的規範。java

什麼是ORM呢?

ORM,即Object-Relational Mapping(對象關係映射),它的做用是在關係型數據庫和業務實體對象之間做一個映射,這樣,咱們在具體的操做業務對象的時候,就不須要再去和複雜的SQL語句打交道,只需簡單的操做對象的屬性和方法。只要提供了持久化類與表的映射關係,ORM框架在運行時就能參照映射文件的信息,把對象持久化到數據庫中。當前ORM框架主要有三種:Hibernate,iBATIS,EclipseLink。

SpringData提供的編程接口:

【1】Repository:最頂層接口,是一個空接口,目的是爲了統一全部的Repository的類型,且能讓組件掃描的時候自動識別;
【2】CrudRepository:提供基礎的增刪改查操做;
【3】PagingAndSortingRepository:提供分頁和排序的操做;
【4】JpaRepository:增長了批量操做的功能;
【5】JpaSpecificationExecutor :組合查詢條件,提供原生SQL查詢。mysql

使用JDBC進行開發:

首先說明例子所設計的數據庫,以下圖:
![圖片描述][1]

1.JDBC工具類

public class JDBCUtil {    
    /*
     * 獲取connection
     * @return 所得到的JDBC的Connection
     */
    public static Connection getConnection() throws ClassNotFoundException, SQLException, IOException
    {
        /*String url = "jdbc:mysql://localhost:3306/spring_data";
        String user = "root";
        String password = "123456";
        String driverClass = "com.mysql.jdbc.Driver";*/
        
        /*
         * 經過讀取配置文件獲取數據庫鏈接所需參數
         */
        InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("database.properties");
        Properties properties = new Properties();
        properties.load(inputStream);
        
        String url = properties.getProperty("jdbc.url");
        String user = properties.getProperty("jdbc.user");
        String password = properties.getProperty("jdbc.password");
        String driverClass = properties.getProperty("jdbc.driverClass");
        Class.forName(driverClass);
        Connection connection =  DriverManager.getConnection(url, user, password);    
        return connection;    
    }    
    /*
     * 釋放資源
     */
    public static void release(ResultSet resultSet,Statement statement,Connection connection)
    {
        /*
         * 釋放resultset
         */
        if(resultSet!=null)
        {
            try {
                resultSet.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(resultSet!=null)
        {
            try {
                resultSet.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        /*
         * 釋放statement
         */
        if(statement!=null)
        {
            try {
                statement.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        /*
         * 釋放connection
         */
        if(connection!=null)
        {
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

附: JDBC數據源配置文件:spring

jdbc.url = jdbc:mysql://localhost:3306/spring_data
jdbc.user = root
jdbc.password = 123456
jdbc.driverClass =com.mysql.jdbc.Driver

2.定義項目中設計的實體類

/**
 * @author 熊濤
 *Student Entity Class
 */
public class Student {

    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

3.Dao層接口的實現

public interface StudentDAO {
    /*
     * 查詢全部學生
     * @return全部學生
     */
    public List<Student> query();
    
    /*
     * 添加學生接口
     */
    public void save(Student student);
}

4.Dao層接口的實現類

/**
 * @author 熊濤
 *StudentDAO接口的實現類,經過最原始的JDBC的方式操做
 */
public class StudetnDAOImpl implements StudentDAO {    
    public List<Student> query() {
        
        List<Student> students = new ArrayList<Student>();
        
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String sql = "select id,name,age from student";
        try {
            connection = JDBCUtil.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            
            Student student = null;
            while(resultSet.next()){
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                
                student = new Student();
                student.setId(id);
                student.setName(name);
                student.setAge(age);
                
                students.add(student);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            JDBCUtil.release(resultSet, preparedStatement, connection);
        }
        
        return students;
    }

    public void save(Student student) {
        
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String sql = "insert into student(name,age) values(?,?)";
        try {
            connection = JDBCUtil.getConnection();
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setString(1, student.getName());
            preparedStatement.setInt(2, student.getAge());
            preparedStatement.executeUpdate();
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(resultSet, preparedStatement, connection);
    }
    }
}

2.使用Spring JDBCTemplate進行開發

1.建立使用Spring-JDBCTemplate所需的配置文件beans.xml目的是將datasource和JDBCTemplate注入進來sql

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_data"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean id="studentDAO" class="com.imooc.dao.StudentDAOSpringJdbcImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
</beans>

2.在Dao層實現類中實現JDBCTemplate數據庫

/**
 * @author 熊濤
 *StudentDAo接口的實現類,經過Spring-JDBC的方式操做
 */
public class StudentDAOSpringJdbcImpl implements StudentDAO {

    //經過set方法注入JdbcTemplate
    private JdbcTemplate jdbcTemplate;
    
    public List<Student> query() {
        
        final List<Student> students = new ArrayList<Student>();
        String sql = "select id,name,age from student";
        jdbcTemplate.query(sql,new RowCallbackHandler(){

            public void processRow(ResultSet rs) throws SQLException {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                
                Student student = new Student();
                student.setId(id);
                student.setName(name);
                student.setAge(age);                    
                students.add(student);                    
            }               
        });
        return students;
    }

    public void save(Student student) {
        String sql = "insert into student(name,age) values(?,?)";
        jdbcTemplate.update(sql,new Object[]{student.getName(),student.getAge()});
    }
    
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

}

3.使用Spring-Data方式進行開發編程

【1】建立使用Spring-Data所需的Spring配置文件      
      <?xml version="1.0" encoding="UTF-8"?>   
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--1 配置數據源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_data"/>
    </bean>

    <!--2 配置EntityManagerFactory-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="packagesToScan" value="com.imooc"/>

        <property name="jpaProperties">
            <props>
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>        
    <!--3 配置事務管理器-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <!--4 配置支持註解的事務-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!--5 配置spring data-->
    <jpa:repositories base-package="com.imooc" entity-manager-factory-ref="entityManagerFactory"/>        
    <context:component-scan base-package="com.imooc"/>       
</beans>

【2】建立項目中所涉及到的實體類服務器

/**
 * @author 熊濤
 *僱員實體類
 *先開發實體類,而後生成對應的數據表
 */
@Entity
@Table(name="test_employee")
public class Employee {

    private Integer id;
    private String name;
    private Integer age;
    
    @GeneratedValue
    @Id
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=20)
    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;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", age=" + age + "]";
    }    
}

【3】建立項目中設計的接口類


 public interface EmployeeRepository extends Repository<Employee,Integer>{

    public Employee findByName(String name);
    public List<Employee> findByNameStartingWithAndAgeLessThan(String name,Integer age);
    public List<Employee> findByNameEndingWithAndAgeLessThan(String name,Integer age);
    public List<Employee> findByNameInOrAgeLessThan(List<String> names,Integer age);
    public List<Employee> findByNameInAndAgeLessThan(List<String> names,Integer age);
        
    @Query("select o from Employee o where id=(select max(id) from Employee t1)")
    public Employee getEmployeeByMaxId();    
    @Query("select o from Employee o where o.name=?1 and o.age=?2")
    public List<Employee> queryParams1(String name,Integer age);
    @Query("select o from Employee o where o.name=:name and o.age=:age")
    public List<Employee> queryParams2(@Param("name")String name,@Param("age")Integer age);
    @Query("select o from Employee o where o.name like %?1%")
    public List<Employee> queryLike1(String name);
    @Query("select o from Employee o where o.name like %:name%")
    public List<Employee> queryLike2(@Param("name")String name);    
    @Query(nativeQuery = true,value = "select count(1) from employee")
    public long getCount();
    
    @Modifying
    @Query("update Employee o set o.age = :age where o.id = :id")
    public void update(@Param("id")Integer id,@Param("age")Integer age);
}

最後附上例子源碼,源碼中還有對於以上代碼功能的測試,測試代碼均位於test包下。
項目源碼:
連接:https://pan.baidu.com/s/1pLcGCUR 密碼:welhapp

相關文章
相關標籤/搜索