1. 程式人生 > >Spring框架——JdbcTemplate(Spring對Jdbc的封裝)

Spring框架——JdbcTemplate(Spring對Jdbc的封裝)

1.JdbcTemplate簡介

Spring提供的一個操作資料庫的技術JdbcTemplate,是對Jdbc的封裝。語法風格非常接近DBUtils。
JdbcTemplate可以直接操作資料庫,加快效率,而且學這個JdbcTemplate也是為宣告式事務做準備,畢竟要對資料庫中的資料進行操縱!
JdbcTemplate中並沒有提供一級快取,以及類與類之間的關聯關係!就像是spring提供的一個DBUtils。
Spring對資料庫的操作使用JdbcTemplate來封裝JDBC,結合Spring的注入特性可以很方便的實現對資料庫的訪問操作。使用JdbcTemplate可以像JDBC一樣來編寫資料庫的操作程式碼

2.為啥要使用Jdbc_template進行開發呢?

Spring對資料庫的操作在jdbc上面做了深層次的封裝,使用spring的注入功能,可以把DataSource註冊到JdbcTemplate之中。
Spring提供的JdbcTemplate對jdbc做了封裝,大大簡化了資料庫的操作。找到Spring JdbcTemplate原始碼,可以看到如下方法:

Connection con = DataSourceUtils.getConnection(getDataSource());

如果直接使用JDBC的話,需要我們載入資料庫驅動、建立連線、釋放連線、異常處理等一系列的動作;繁瑣且程式碼看起來不直觀。
此外,Spring提供的JdbcTempate能直接資料物件對映成實體類,不再需要獲取ResultSet去獲取值/賦值等操作,提高開發效率;
如下:return (User) jdbcTemplate.queryForObject("select * from tb_test1 where id = 100", User.class)

3.配置環境

①匯入jar包

  1. IOC容器需要的jar包
    commons-logging-1.1.3.jar
    spring-aop-4.0.0.RELEASE.jar //註解會使用到的包
    spring-beans-4.0.0.RELEASE.jar
    spring-context-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    spring-expression-4.0.0.RELEASE.jar

  2. MySQL驅動、C3P0jar包
    c3p0-0.9.1.2.jar
    mysql-connector-java-5.1.37-bin.jar

  3. JdbcTemplate需要的jar包
    spring-jdbc-4.0.0.RELEASE.jar
    spring-orm-4.0.0.RELEASE.jar
    spring-tx-4.0.0.RELEASE.jar

②在IOC容器中配置資料來源

    <!-- 載入properties檔案中 資訊 -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <!-- 配置資料來源 -->
        <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.passowrd}"></property>
            <property name="jdbcUrl" value="${jdbc.url}"></property>
            <property name="driverClass" value="${jdbc.driver}"></property>
        </bean>

其中jdbc.properties檔案內容:
jdbc.user=root
jdbc.passowrd=123456
jdbc.url=jdbc:mysql://localhost:3306/student
jdbc.driver=com.mysql.jdbc.Driver

③在IOC容器中配置JdbcTemplate物件的bean,並將資料來源物件裝配到JdbcTemplate物件中.

<!-- 配置JdbcTemplate對應的bean, 並裝配dataSource資料來源屬性-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="comboPooledDataSource"></property>
        </bean>

4.實驗:

實驗1:測試資料來源

    @Test
    public void test() throws SQLException {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource bean = ioc.getBean(DataSource.class);
        System.out.println(bean.getConnection());
    }

實驗2:將sid=21020的記錄的salary欄位更新為1300【更新操作】

public class TestDataSource {
        private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        private JdbcTemplate template=ioc.getBean(JdbcTemplate.class);

        @Test
        public void test01(){
            //實驗2:將sid=21020的記錄的age欄位更新為13
            String sql = "UPDATE student SET age = ? WHERE sid = ?";
            template.update(sql, 13,21020);//第一個是sql語句,後面的按著順序傳入引數即可,這個update方法是接收的可變引數!
        }
    }

從上述實驗中就可以看到,該操作不用我們自己再去獲取資料庫連線資訊了,而是直接傳遞sql語句及其引數!

實驗3:批量插入

    public class TestDataSource {
                private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
                private JdbcTemplate template=ioc.getBean(JdbcTemplate.class);
                @Test
                public void testBatch(){
                    String sql="INSERT INTO employee(`emp_name`,`salary`) VALUES(?,?)";
                    //執行sql語句需要傳遞的引數
            //      Object[][] params = new Object[3][2];
            //      params[0] = new Object[]{"Tom2015",1000};
            //      params[1] = new Object[]{"Tom2016",2000};
            //      params[2] = new Object[]{"Tom2017",3000};
            //      
                    List<Object[]> list = new ArrayList<Object[]>();
                    list.add(new Object[]{"Tom2015",1000});
                    list.add(new Object[]{"Tom2016",2000});
                    list.add(new Object[]{"Tom2017",3000});

                    template.batchUpdate(sql, list);
                }
        }

實驗4:查詢emp_id=5的資料庫記錄,封裝為一個Java物件返回
分析:封裝為一個物件返回的話,首先我們需要有一個與資料表對應的實體類!

public class TestDataSource {
            private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
            private JdbcTemplate template=ioc.getBean(JdbcTemplate.class);

            @Test
            public void test01(){
                //需要注意的是:sql語句中的別名要與對應實體類的屬性名保持一致!
                String sql = "SELECT emp_id AS empId,emp_name AS empName,salary FROM employee WHERE emp_id=?";

                //RowMapper是一個介面,這裡我們使用其子類
                RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<Employee>(Employee.class);
                //最後一個引數是可變引數,用於向sql語句中依次傳遞引數!
                Employee employee = template.queryForObject(sql, rowMapper, 5);
                System.out.println(employee);
            }
        }

實驗5:查詢salary>4000的資料庫記錄,封裝為List集合返回

    public class TestDataSource {
            private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
            private JdbcTemplate template=ioc.getBean(JdbcTemplate.class);

            @Test
            public void test01(){
                //需要注意的是:sql語句中的別名要與對應實體類的屬性名保持一致!
                String sql = "SELECT emp_id AS empId,emp_name AS empName,salary FROM employee WHERE salary > ?";

                //RowMapper是一個介面,這裡我們使用其子類
                RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<Employee>(Employee.class);
                //該query方法查詢出來的是一個list列表,query方法的最後一個引數是可變引數!
                List<Employee> list = template.query(sql, rowMapper, 4000);

                for (Employee employee : list) {
                    System.out.println(employee);
                }
            }
        }

從上面可以看出,查詢結果是一個實體還是一個list列表是靠template物件的不同方法實現的!

實驗6:查詢最大salary

public class TestDataSource {
        private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        private JdbcTemplate template=ioc.getBean(JdbcTemplate.class);

        @Test
        public void test01(){
            String sql = "SELECT MAX(salary) FROM employee";
            //需要指定返回值的型別,而且型別必須是包裝型別
            Double maxSalary = template.queryForObject(sql, Double.class);
            System.out.println(maxSalary);
        }
    }

實驗7:使用帶有具名引數的SQL語句插入一條員工記錄,並以Map形式傳入引數值
具名引數:是指基於名稱的,前面我們使用的都是用?作為佔位符,然後是使用基於位置的!
如果要使用具名引數的sql語句就必須在spring配置檔案中配置NamedParameterJdbcTemplat這個模板類,而不能使用
原來的JdbcTemplate,因為JdbcTemplate不能完成這樣的任務!

            <!-- 載入properties檔案中 資訊 -->
            <context:property-placeholder location="classpath:jdbc.properties"/>
            <!-- 配置資料來源 -->
            <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property name="user" value="${jdbc.user}"></property>
                <property name="password" value="${jdbc.passowrd}"></property>
                <property name="jdbcUrl" value="${jdbc.url}"></property>
                <property name="driverClass" value="${jdbc.driver}"></property>
            </bean>

            <!-- 配置JdbcTemplate對應的bean, 並裝配dataSource資料來源屬性-->
            <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="comboPooledDataSource"></property>
            </bean>
            <!-- 為了執行帶有具名引數的SQL語句,需要配置NamedParameterJdbcTemplate -->
            <!-- 該NamedParameterJdbcTemplate類沒有無參構造器,需要傳入JdbcTemplate物件或者資料來源物件[DataSource] -->
            <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
                <!-- 不能使用property標籤配置哦 -->
                <constructor-arg ref="jdbcTemplate"></constructor-arg>
            </bean>
public class TestDataSource {
            private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
            private NamedParameterJdbcTemplate namedJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);

            @Test
            public void test01(){
                String sql="INSERT INTO employee(`emp_name`,`salary`) VALUES(:paramName,:paramSalary)";
                Map<String,Object> paramMap = new HashMap<String,Object>();
                paramMap.put("paramName","張學友" );
                paramMap.put("paramSalary",1000);

                namedJdbcTemplate.update(sql, paramMap);
            }
        }

實驗8:重複實驗7,以SqlParameterSource形式傳入引數值

public class TestDataSource {
            private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
            private NamedParameterJdbcTemplate namedJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);

            @Test
            public void test01(){
                String sql="INSERT INTO employee(`emp_name`,`salary`) VALUES(:empName,:salary)";
                //該BeanPropertySqlParameterSource類構造器需要一個物件引數,該物件引數是一個封裝了sql語句引數的物件!
                //此時要求物件的屬性名要和sql中的引數名保持一致!這裡我們使用Employee物件來完成
                Employee employee= new Employee(null, "郭富城", 1500);
                //以實體物件的形式封裝具名引數和值
                SqlParameterSource source = new BeanPropertySqlParameterSource(employee);

                namedJdbcTemplate.update(sql, source);
            }
        }

實驗9:建立JdbcTemplateDao,自動裝配JdbcTemplate物件
1.建立dao類:

    @Repository
    public class JdbcTemplateDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;

        public void update(String sql,Object ...args){
            jdbcTemplate.update(sql, args);
        }
    }

2.配置spring的配置檔案

<!-- 配置掃描的包 -->
                <context:component-scan base-package="com.neuedu.dao"></context:component-scan>
                <!-- 載入properties檔案中 資訊 -->
                <context:property-placeholder location="classpath:jdbc.properties"/>
                <!-- 配置資料來源 -->
                <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                    <property name="user" value="${jdbc.user}"></property>
                    <property name="password" value="${jdbc.passowrd}"></property>
                    <property name="jdbcUrl" value="${jdbc.url}"></property>
                    <property name="driverClass" value="${jdbc.driver}"></property>
                </bean>

                <!-- 配置JdbcTemplate對應的bean, 並裝配dataSource資料來源屬性-->
                <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                    <property name="dataSource" ref="comboPooledDataSource"></property>
                </bean>

3.測試該dao

 public class TestDataSource {
    private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
    private NamedParameterJdbcTemplate namedJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);

    @Test
    public void test01(){
        JdbcTemplateDao dao = ioc.getBean(JdbcTemplateDao.class);
        String sql = "INSERT INTO employee(`emp_name`,`salary`) VALUES(?,?)";
        dao.update(sql, "比爾蓋茨",10000000);

    }
}