• 《Spring》(十七)---- JDBC访问数据


    基于JdbcTemplate的数据查询

    用于查询的回调接口定义主要有以下三种:

    1. ResultSetExtractor
    public interface ResultSetExtractor {
        Object extractData(ResultSet rs) throws SQLException, DataAccessException;
    }

      2. RowCallbackHandler  只关注单行结果的处理。

    public interface RowCallbackHandler {
        void processRow(ResultSet rs) throws SQLException;
    }

      3. RowMapper 只关注单行结果。

    public interface RowMapper {
        Object mapRow(ResultSet rs, int rowNum) throws SQLException;
    }

    Example: 

    package com.ivy.SpringJdbc;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.dao.DataAccessException;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.ResultSetExtractor;
    import org.springframework.jdbc.core.RowCallbackHandler;
    import org.springframework.jdbc.core.RowMapper;
    
    public class CallbackDemo {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        public List<Customer> getCustomersByResultSetExtractor() {
            List<Customer> customerList = (List<Customer>)jdbcTemplate.query("select * from customer", new ResultSetExtractor<List<Customer>>() {
    
                @Override
                public List<Customer> extractData(ResultSet rs) throws SQLException,
                        DataAccessException {
                    List<Customer> customers = new ArrayList<Customer>();
                    while(rs.next()) {
                        Customer customer = new Customer();
                        customer.setFirstName(rs.getString(1));
                        customer.setLastName(rs.getString(1));
                        customer.setAge(rs.getInt(3));
                        customers.add(customer);
                    }
                    return customers;
                }
                
            });
            return customerList;
        }
        
        public List<Customer> getCustomersByRowCallbackHandler() {
            final List<Customer> customers = new ArrayList<Customer>();
            jdbcTemplate.query("select * from customer", new RowCallbackHandler() {
    
                @Override
                public void processRow(ResultSet rs) throws SQLException {
                    Customer customer = new Customer();
                    customer.setFirstName(rs.getString(1));
                    customer.setLastName(rs.getString(1));
                    customer.setAge(rs.getInt(3));
                    customers.add(customer);
                }
                
            });
            return customers;
        }
        
        public List<Customer> getCustomersByRowMapper() {
            List<Customer> customers = jdbcTemplate.query("select * from customer", new RowMapper<Customer>() {
    
                @Override
                public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Customer customer = new Customer();
                    customer.setFirstName(rs.getString(1));
                    customer.setLastName(rs.getString(1));
                    customer.setAge(rs.getInt(3));
                    return customer;
                }
            });
            return customers;
        }
    }

    基于JdbcTemplate的数据更新

    int update(String sql)

    int update(String sql, Object[] args)

    int update(String sql, Object[] args, int[] argTypes)

    批量更新数据

    int[] batchUpdate(String[] sql)

    int[] batchUpdate(String sql, BatchPreparedStatementSetter pss)

    Example

    package com.ivy.SpringJdbc;
    
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.BatchPreparedStatementSetter;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    public class BatchUpdateDemo {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        public int[] insertNewCustomers(final List<Customer> customers) {
            return jdbcTemplate.batchUpdate("insert into customer value(?,?,?)", new BatchPreparedStatementSetter() {
                
                @Override
                public void setValues(PreparedStatement ps, int i) throws SQLException {
                    Customer customer = (Customer)customers.get(i);
                    ps.setString(1, customer.getFirstName());
                    ps.setString(2, customer.getLastName());
                    ps.setInt(3, customer.getAge());
                }
                
                @Override
                public int getBatchSize() {
                    return customers.size();
                }
            });
        }
    }

    调用存储过程

    存储过程是定义于数据库服务器端的计算单元。对于涉及多表数据而只使用SQL无法完成的计算,我们可以通过在数据库服务器端编写并部署存储过程的方式来实现。相对于将这些计算逻辑转移到客户端进行,使用存储过程的好处在于,可以避免像客户端计算那样在网络间来回传送数据导致的性能损失,因为存储过程的所有计算全部在服务器端完成。如果计算设计多个数据表,大量的数据查询和更新,那么使用存储过程代替客户端计算是比较合适的做法。

    例如

    CREATE PROCEDURE CountTable(IN tableName varchar(1000), OUT sqlStr varchar(1000), INOUT v INT)
    BEGIN
        set @flag = v;
        set @sql = CONCAT('select count(*) into @res from'', tableName, 'where ACTIVE_FLAG=?');
        PREPARE stmt FROM @sql;
        EXECUTE stmt using @flag;
        DEALLOCATE PREPARE stmt;
        set v = @res;
        set sqlStr = @sql;
    END

     

    Object result = jdbcTemplate.execute("call CountTable(?,?,?)", new CallableStatementCallback() {
    
                @Override
                public Object doInCallableStatement(CallableStatement cs)
                        throws SQLException, DataAccessException {
                    cs.setString(1, "tableName");
                    cs.setInt(3, 1);
                    cs.registerOutParameter(2, Types.INTEGER);
                    cs.registerOutParameter(3, Types.INTEGER);
                    
                    cs.execute();
                    
                    Map resultMap = new HashMap();
                    resultMap.put("SQL", cs.getString(2));
                    resultMap.put("COUNT", cs.getInt(3));
                    return resultMap;
                }
                
            });

    递增主键生成策略的抽象

     1,基于独立主键表的DataFieldMaxValueIncrementer。它依赖于为每个数据表单独定义的主键表,主键表中定义的主键可以根据需要获取并递增,并且可以设置每次获取的CacheSize以减少访问数据库资源的频度。

     2,基于数据库Sequence的DataFiledMaxValueIncrementer。数据库本身支持基于Sequence的主键生成。

    String中的LOB类型处理

    Spring提出一套基于LOB数据处理类,用于屏蔽各数据库驱动在处理LOB数据方式上的差异性。

    public interface LobHandler {
        byte[] getBlobAsBytes(ResultSet rs, String columnName) throws SQLException;
        byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException;
        InputStream getBlobAsBinaryStream(ResultSet rs, String columnName) throws SQLException;
        InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException;
        String getBlobAsString(ResultSet rs, String columnName) throws SQLException;
        String getBlobAsString(ResultSet rs, int columnIndex) throws SQLException;
        InputStream getBlobAsAsciiStream(ResultSet rs, String columnName) throws SQLException;
        InputStream getBlobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException;
        Reader getBlobAsCharStream(ResultSet rs, String columnName) throws SQLException;
        Reader getBlobAsCharStream(ResultSet rs, int columnIndex) throws SQLException;
        LobCreator getLobCreator();
    }

      LobCreator的职责主要在于LOB数据的创建,它让我们能够以统一的方式创建LOB数据。我们将在插入或者更新LOB数据的时候使用它。

     DefaultLobHandlerDemo.java

    package com.ivy.SpringJdbc;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.dao.DataAccessException;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;
    import org.springframework.jdbc.support.lob.DefaultLobHandler;
    import org.springframework.jdbc.support.lob.LobCreator;
    import org.springframework.jdbc.support.lob.LobHandler;
    
    public class DefaultLobHandlerDemo {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        public void saveImage() throws FileNotFoundException {
            final File imageFile = new File("snow_image.jpg");
            final InputStream ins = new FileInputStream(imageFile);
            LobHandler lobHandler = new DefaultLobHandler();
            jdbcTemplate.execute("insert into images(id, filename, entity, description) values(?,?,?,?)", new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
    
                @Override
                protected void setValues(PreparedStatement ps, LobCreator lobCreator)
                        throws SQLException, DataAccessException {
                    ps.setInt(1, 2);
                    ps.setString(2, "snow_image.jpg");
                    lobCreator.setBlobAsBinaryStream(ps, 3, ins, (int)imageFile.length());
                    ps.setString(4, "nothing to say");
                }
    
                
            });
            IOUtils.closeQuietly(ins);
        }
    }

    NamedParameterJdbcTemplate

    example 1 :

    DataSource dataSource = ...;
    NamedParameterJdbcTemplate npJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    
    SqlParameterSource parameterSource = new MapSqlParameterSource("filename","snow_image.jpg");
    int count = npJdbcTemplate.queryForInt("select count(*) from images where filaname=:filename", parameterSource);

    example 2 :

    DataSource dataSource = ...;
    NamedParameterJdbcTemplate npJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    
    Image image = new Image();
    image.setFilename("snow_image.jpg");
    
    
    SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(image);
    int count = npJdbcTemplate.queryForInt("select count(*) from images where filaname=:filename", parameterSource);

    SimpleJdbcTemplate

    SimpleJdbcTemplate集JdbcTemplate和NamedParameterJdbcTemplate的功能于一身。

    example:

    package com.ivy.SpringJdbc;
    
    import java.awt.Image;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import javax.activation.DataSource;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
    import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
    import org.springframework.jdbc.support.lob.DefaultLobHandler;
    import org.springframework.jdbc.support.lob.LobHandler;
    
    public class SimpleJdbcTemplateDemo {
    
        @Autowired
        private DataSource dataSource;
        
        public void test() {
            SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
            final LobHandler lobHandler = new DefaultLobHandler();
            String SQL = "select count(*) from images where filename = ? and description = ?";
            ParameterizedRowMapper<Image> rowMapper = new ParameterizedRowMapper<T>() {
    
                @Override
                public T mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Image image = new Image();
                    image.setId(rs.getInt(1));
                    image.setFilename(rs.getString(2));
                    image.setEntity(lobHandler.getBlobAsBytes(rs, 3));
                    image.setDescription(rs.getString(4));
                    return image;
                }
            };
         Image image = simpleJdbcTemplate.queryForObject(SQL, rowMapper, "snow_image.jpg", "nothing to say");
    } }

    DataSource访问方式

    1, 本地DataSource访问

    在容器的配置文件中进行简单的配置即可。

    2,远程DataSource访问

    对于运行于应用服务器的程序或者分布式应用来说,通过JNDI访问DataSource是最常见方式

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jdniName">
            <value>java:env/myDataSource</value>
        </property>
    </bean>
  • 相关阅读:
    30 Day Challenge Day 11 | Leetcode 55. Jump Game
    30 Day Challenge Day 11 | Leetcode 11. Container With Most Water
    30 Day Challenge Day 10 | Leetcode 701. Insert into a Binary Search Tree
    30 Day Challenge Day 10 | Leetcode 1. Two Sum
    30 Day Challenge Day 10 | Leetcode 3. Longest Substring Without Repeating Characters
    30 Day Challenge Day 9 | Leetcode 425. Word Squares
    30 Day Challenge Day 8 | Leetcode 200. Number of Islands
    30 Day Challenge Day 7 | Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
    30 Day Challenge Day 7 | Hackerrank: Tree: Huffman Decoding
    30 Day Challenge Day 6 | Leetcode 92. Reverse Linked List II
  • 原文地址:https://www.cnblogs.com/IvySue/p/6610380.html
Copyright © 2020-2023  润新知