zoukankan      html  css  js  c++  java
  • Spring学习进阶(四) Spring JDBC

    Spring JDBC是Spring所提供的持久层技术。主要目的是降低使用JDBC API的门槛,以一种更直接,更简洁的方式使用JDBC API。在Spring JDBC里用户仅需要做哪些比不可少的事,而将资源获取,Statement创建,异常处理,资源释放等繁杂而乏味的工作交交给Spring.
    一、使用Spring JDBC
    使用JDBC编写数据库的时候,由于JDBC API过于底层,开发者不但需要编写数据操作代码,还需要编写获得JDBC连接、异常处理、释放资源等。而Spring JDBC通过模板和回调机制大大降低了使用JDBC的复杂度,借助JdbcTemplate用户只需要编写实际操作的代码就可以了、
    1、使用JdbcTemplate创建一张表
    DriverManagerDataSource ds=new DriverManagerDataSource(); //创建数据源
    ds.setDriverClassName(com.mysql.jdbc.Driver);
    ds.setUrl("jdbc://localhost:3309/sampledb");
    ds.setUsername("root");
    ds.setPassword("1234");
    JdbcTemplate jdbcTemplate=new JdbcTemplate();//生成一个JdbcTemplate的实例
    jdbc.setDataSource(ds);
    String sql="create table t_user(user_id int primary key,user_name varchar(60))";//创建一张表
    jdbcTemplate.execute(sql);
    在上述中,使用DriverManagerDataSource创建一个数据源,紧接着,创建了一个JdbcTemplate对象,然后使用该对象执行SQL语句。JdbcTemplate是线程安全的所有的DAO都共享一个JdbcTemplate实例。因此上述中创建数据源和生成JdbcTemplate都可以在Spring配置文件中统一定义了。
    2、在DAO中使用JdbcTemplate
    @Repository
    public class ViewSpaceDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void initDb() {
    String sql = "create table t_user(user_id int primary key,user_name varchar(60))";
    jdbcTemplate.execute(sql);
    }}
    在Spring配置文件中定义JdbcTemplate并注入每个DAO中。
    <!--扫描包以注册注解声明的Bean-->
    <context:component-scan base-package="com.smart"/>
    <!--配置数据源-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close"
    p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.url}"
    p:username="${jdbc.username}"
    p:password="${jdbc.password}"/>
    <!--声明JdbcTemplate-->
    <bean id="jdbcTemplate"
    class="org.springframework.jdbc.core.JdbcTemplate"
    p:dataSource-ref="dataSource"/>
    在Spring配置文件中配置DAO一般分为4个步骤:
    1)定义DataSource
    2)定义JdbcTemplate
    3)声明一个抽象的Bean,以便所有DAO复用配置JdbcTemplate属性的配置
    4)配置具体的DAO
    实战经验:
    Spring几乎为所有的模板类都提供相应的支持类,与JdbcTemplate对应的支持类为JdbcDaoSupport.JdbcDaoSupport内部定义了JdbcTemplate的成员变量,开发者可以通过扩展JdbcDaoSupport定义自己的Dao,但是随着Bean的注解配置逐渐成为主流配置方式。这种方法便不再可用,因为直接继承JdbcDaoSupport无法对JdbcTemplate成员变量应用@Autowired注解,所以,一般是自己定义一个BaseDao,在BaseDao中定义JdbcTemplate成员变量,并使用@Autowired注解。还会在BaseDao中定义一些通用的功能,如声明JdbcTemplate,分页查询等、
    二、基本的数据操作
    数据库的增删改查以及存储过程调用时最基本的数据库操作,JdbcTemplate提供了众多的方法,通过JdbcTemplate用户可以用最简单的方法完成这些数据操作。
    1、更改数据
    JdbcTemplate提供了若干update()方法,允许用户对数据表记录进行更改和删除操作。
    @Repository
    public class ViewSpaceDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void addViewSpace(final ViewSpace viewSpace) {
    final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(?,?,?)";
    Object[] params = new Object[] { viewSpace.getSpaceName(),viewSpace.getDescription(),viewSpace.getAddress() };
    // 方式1
    jdbcTemplate.update(sql, params);}
    }
    JdbcTemplate在内部通过PreparedStatement执行SQL语句,左移可以使用绑定参数的SQL语句。在sql中?代表一个占位符,而param中的是用于填充占位符的参数数组,在最后直接通过int update(String sql,Object[]args)方法进行表数据的更新
    通过update(String sql,Object[]args)方法为SQL语句的占位符绑定参数时,并没有显示指定对应字段的数据类型。Spring直接让PreparedStatement进行猜测。更好的方法是使用int update(String sql,Object[]args,int[]argTypes)显示指定每个占位符所对应的字段数据类型
    此时上述的 jdbcTemplate.update(sql, params);}就会变为jdbcTemplate.update(sql, params,new int[]{Types.VARCHAR,Types.VARCHAR});
    除了以上的两个update()方法,JdbcTemplate还提供了以下几个功能相似的重载方法
    int update(String sql):为不带占位符的SQL语句所提供的方法
    int update(String sql,Object...args):使用不定参数的方法
    int update(String sql,PreparedStatementSetterpss):PreparedStatementSetter是一个回调接口,他定义了一个void setValues(PreparedStatement ps)接口方法。JdbcTemplate使用SQL语句创建出PreparedStatement实例后,将调用接口执行绑定参数的操作。
    jdbcTemplate.update(sql, new PreparedStatementSetter() { public void
    setValues(PreparedStatement ps) throws SQLException { ps.setString(1,forum.getForumName()); ps.setString(2, forum.getForumDesc()); } });
    int update(PreparedStatementCreator psc):这也是一个回调接口,他负责创建一个PreparedStatement实例,该接口回调定义了一个PreparedStatement createPrepareStatement(Connection con)方法
    KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(new PreparedStatementCreator() {
    public PreparedStatement createPreparedStatement(Connection conn)
    throws SQLException {
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.setString(1, viewSpace.getSpaceName());
    ps.setString(2, viewSpace.getDescription());
    ps.setString(3, viewSpace.getAddress());
    return ps;
    }
    }, keyHolder);
    viewSpace.setSpaceId(keyHolder.getKey().intValue());
    protected int update(PreparedStatementCreator psc,PreparedStatementSetter pss):联合使用PreparedStatementCreator和PreparedStatementSetter回调。
    2、返回数据库的表自增主键值
    用户经常使用数据的自增字段作为表主键,即主键值不在应用层产生,而是在新增记录时数据库产生。
    当新增记录时允许将数据库自动产生的主键值绑定到Statement或PreparedStatement中,使用Statement时,可以通过如下方法绑定主键值。
    int executeUpdate(String sql,int autoGenerateKeys)
    也可以通过Connection创建绑定自增值的PreparedStatement
    PreparedStatement prepareStatement(String sql,int autoGenerateKeys)
    当autoGeneratedKeys参数设置为Statement.RETURN_GENERATED_KEYS值时即可绑定数据库产生的主键值,设置为Statement._NO_GENERATED_KEYS不绑定主键值
    Statement stmt=conn.createStatement();
    String sql="INSERT INTO T_VIEW(space_name,description)VALUES('拨浪鼓','国家级旅游度假区')";
    stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);//指定绑定自增主键值
    if(rs.next()){int key=rs.getInt();}//获取对应的表自增主键值
    3、批量更改数据
    public int[] batchUpdate(String[]sql):多条SQL语句组成一个数组,该方法以批量方式执行这些SQL语句,Spring在内部使用JDBC提供的批量更新API完成操作,如果底层的Jdbc Driver不支持批量更新操作,Spring将采用逐条更新的方式模拟批量更新
    int[] batchUpdate(String sql,BatcgPreparedStatementSetter pss):使用本方法对于统一结构的带参SQL语句多次进行数据更次年操作。通过BatchPreparedStatementSETTER回调接口进行批量参数的绑定工作。而BatchPreparedStatementSetter又定义了两个方法
    int getBatchSize():指定本批次的大小
    void setValues(PreparedStatement ps ,int i):为指定的PreparedStatement设置参数
    public void addViewSpaces(final List<ViewSpace> viewSpaces) {
    final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(?,?,?)";
    jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
    public int getBatchSize() {
    return viewSpaces.size();
    }

    public void setValues(PreparedStatement ps, int index)
    throws SQLException {
    ViewSpace viewSpace = viewSpaces.get(index);
    ps.setString(1, viewSpace.getSpaceName());
    ps.setString(2, viewSpace.getDescription());
    ps.setString(3, viewSpace.getAddress());
    }
    });
    jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
    public int getBatchSize() {
    return viewSpaces.size();
    }

    public void setValues(PreparedStatement ps, int index)
    throws SQLException {
    ViewSpace viewSpace = viewSpaces.get(index);
    ps.setString(1, viewSpace.getSpaceName());
    ps.setString(2, viewSpace.getDescription());
    ps.setString(3, viewSpace.getAddress());
    }
    });
    }
    BatchPreparedStatementSetter是一次性批量提交数据,而不会分批提交,getBatchSize()是整批的大小,所以,如果希望一个LIST钟的数据通过BatchPreparedStatementSETTER批量更新到数据库中getBatchSize()就应该设置为List的大小。
    4、数据查询
    使用RowCallbackHandler处理结果集
    Spring提供了org.springframework.jdbc.core.RowCallbackHandler回调接口,通过该接口可以定义如何从结果集中获取数据。该接口只有一个方法void processRow(ResultSet rs) throw SQLException.Spring会遍历结果集,对结果集中的每一行调用RowCallbackHandler回调接口处理数据,所以我们无须调用ResultSet的next()方法,而只是定义如何获取结果行中的数据的逻辑就可以了。
    示例:通过id获取数据
    public ViewSpace getViewSpace(final int spaceId) {
    String sql = "SELECT space_name,description,address FROM t_view_space WHERE space_id=?";
    final ViewSpace viewSpace = new ViewSpace();

    jdbcTemplate.query(sql, new Object[] { spaceId },
    new RowCallbackHandler() {//将结果集数据航中的数据抽取到viewSpace对象中
    public void processRow(ResultSet rs) throws SQLException {
    viewSpace.setSpaceId(spaceId);
    viewSpace.setSpaceName(rs.getString("space_name"));
    viewSpace.setDescription(rs.getString("description"));
    viewSpace.setAddress(rs.getString("address"));
    }
    });
    return viewSpace;
    }
    示例:返回多条数据
    public List<ViewSpace> getViewSpaces(final int fromId, final int toId) {
    String sql = "SELECT space_id, SPACE_NAME,description,address FROM t_view_space WHERE space_id between ? and ?";
    // 方法1:使用RowCallbackHandler接口
    final List<ViewSpace> viewSpaces = new ArrayList<ViewSpace>();
    jdbcTemplate.query(sql,new Object[]{fromId,toId},new
    RowCallbackHandler(){ public void processRow(ResultSet rs) throws//将结果集中的数据映射到List中
    SQLException {
    viewSpace = new ViewSpace();
    viewSpace.setSpaceId(rs.getInt("space_id"));
    viewSpace.setSpaceName(rs.getString("space_name"));
    viewSpace.setDescription(rs.getString("description"));
    viewSpace.setAddress(rs.getString("address"));
    viewSpaces.add(viewSpace);
    }}); return forums;

    }
    5、查询单值数据
    如果查询的结果仅有一个值,可以用更简单的方式获得结果的值。JdbcTemplate为获取结果集的单值数据提供了3个方法,分别用于获取int long 的单值,其他类型的单值以Object类型返回。
    int类型的单值查询接口:
    int queryForInt(String sql)
    int queryForInt(String sql,Object...args)
    int queryForInt(String sql,Object[]args,int[]argTypes)
    示例:
    public int getViewSpaceNum(){
    String sql="select count(*) from t_view_space ";
    return getJdbcTemplate。queryForInt(sql);
    }
    long类型的单值查询接口:
    long queryForLongString sql)
    long queryForLong(String sql,Object...args)
    long queryForLong(String sql,Object[]args,int[]argTypes)
    其他类型的单值查询接口:
    <T> queryForObject(String sql,Class<T>requiredType)
    <T> queryForObject(String sql,Object[]args,Class<T>requiredType)
    <T> queryForObject(String sql,Object[]args,int[]argTypes,Class<T>requiredType)
    <T> queryForObject(String sql,Object[]args,int[]argTypes,RowMapper<T>rowMapper)
    <T> queryForObject(String sql,Object[]args,RowMapper<T>rowMapper)
    <T> queryForObject(String sql,RowMapper<T>rowMapper)
    6、调用存储过程
    JdbcTemplate提供了两个调用存储过程的接口方法
    1)<T>T execute(String callString,CallableStatementCallback<T>action)
    用户同callString参数指定调用存储过程的SQL语句。第二个参数CallableStatementCallback<T>是一个回调接口,该接口只有一个方法T DoInCallableStatement(CallableStatement cs)影虎可以在该方法中进行输入参数绑定,输出参数注册一级返回数据处理等操作
    2)<T> T execute(CallableStatementCreator csc,CallableStatementCallback<T>action)
    该接口方法使用CallableStatementCreator创建CallableStatement,CallableStatementCreator定义了一个方法:CallableStatement createCallableStatement(Connection con),他使用Connection实例创建CallableStatement对象。CallableStatementCallable<T>负责处理存储过程的返回结果。
    Spring提供了创建CallableStatementCreator的工厂类CallableStatementCreatorFactory,通过该工厂类可以简化CallableStatementCreator的实例的创建工作。
    例如创建一个存出过场一个入参in_space_id一个出参out_num
    public int getViewPointNum(final int spaceId){
    String sql="{call P_GET_VIEW_POINT_NUM(?,?)}";//调用存储过程的SQL语句
    Integet num=jdbcTemplate.execute(sql,new CallableStatementCallback<Integer>(){
    public Integer doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException{
    cs.setInt(1,spaceId);//绑定入参
    cs.registerOutParameter(2,Types.INTEGER);//注册输出参数
    cs.execute();
    return cs.getInt(2); }//获取输出参数的值
    });
    return num;
    }
    或者:
    public int getSpaceViewPointNum(final int spaceId) {
    String sql = "{call P_GET_VIEW_POINT_NUM(?,?)}";
    CallableStatementCreatorFactory fac = new CallableStatementCreatorFactory(sql);//以一个SQL语句为入参创建CallableStatementCreator工厂实例
    fac.addParameter(new SqlParameter("spaceId", Types.INTEGER));//设置存储过程的入参
    fac.addParameter(new SqlOutParameter("pointNum", Types.INTEGER));//设置存储过程的出参
    Map<String, Integer> paramsMap = new HashMap<String, Integer>();
    paramsMap.put("spaceId", spaceId);//为前面的入参指定参数值
    CallableStatementCreator csc = fac.newCallableStatementCreator(paramsMap);
    Integer num = jdbcTemplate.execute(csc, new CallableStatementCallback<Integer>() {//通过new CallableStatementCallback<Integer>创建一个CallableStatementCreator
    public Integer doInCallableStatement(CallableStatement cs)
    throws SQLException, DataAccessException {
    cs.execute();
    return cs.getInt(2);
    }
    });
    return num;
    }

    三、BLOB/CLOB类型数据的操作
    1、插入Lob类型的数据
    用于保存数据的表有两个Lob字段,其中description是CLOB类型,而imageFile是BLOB类型
    package com.smart.dao;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.sql.*;

    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import com.smart.domain.ViewPoint;
    import oracle.jdbc.OracleConnection;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.dao.DataAccessException;
    import org.springframework.jdbc.LobRetrievalFailureException;
    import org.springframework.jdbc.core.CallableStatementCallback;
    import org.springframework.jdbc.core.CallableStatementCreator;
    import org.springframework.jdbc.core.CallableStatementCreatorFactory;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.jdbc.core.SqlOutParameter;
    import org.springframework.jdbc.core.SqlParameter;
    import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;
    import org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor;
    import org.springframework.jdbc.datasource.DataSourceUtils;
    import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
    import org.springframework.jdbc.support.lob.LobCreator;
    import org.springframework.jdbc.support.lob.LobHandler;
    import org.springframework.jdbc.support.rowset.SqlRowSet;
    import org.springframework.stereotype.Repository;
    import org.springframework.util.FileCopyUtils;

    @Repository
    public class ViewPointDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Autowired
    private LobHandler lobHandler;//定义LobHandler属性
    @Autowired
    private DataFieldMaxValueIncrementer incre;
    public void addViewPoint(final ViewPoint viewPoint) {
    String sql = " INSERT INTO t_view_point(point_id,space_id,point_name,ticket_price,img_file,description)"
    + " VALUES(?,?,?,?,?,?)";
    jdbcTemplate.execute(sql, new AbstractLobCreatingPreparedStatementCallback(this.lobHandler) {
    protected void setValues(PreparedStatement ps, LobCreator lobCreator)
    throws SQLException {
    //1:固定主键
    //ps.setInt(1,1);

    //2:通过自增键指定主键值LobHandler属性
    ps.setInt(1, incre.nextIntValue());
    ps.setInt(2, viewPoint.getSpaceId());
    ps.setString(3, viewPoint.getPointName());
    ps.setDouble(4, viewPoint.getTicketPrice());
    lobCreator.setClobAsString(ps, 6, viewPoint.getDescription());//设置Clob字段
    lobCreator.setBlobAsBytes(ps, 5, viewPoint.getImgFile());//设置Blob字段
    }
    });
    }}
    首先在ViewPointDao中引入一个LobHandler属性,并通过jdbcTemplate.execute(sql, new AbstractLobCreatingPreparedStatementCallback(this.lobHandler)方法完成插入Lob数据的操作,通过匿名内部类的方式定义LobCreatingPreparedStatementCallback抽象类的子类,其构造函数需要一个LobHandler入参。
    在匿名类中实现了父类的抽象方法setValues(PreparedStatement ps,LobCreator lobCreator)在该方法中,通过lobCreator操作Lob对象。
    配置文件中做更改:
    <bean id="nativeJdbcExtractor"
    class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
    lazy-init="true"/>

    <bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"<!--使用设置本地JDBC对象抽取只要不是oracle9i则可以将OracleLobHandler改为DefaultLobHandler而且也不需要 <bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"<!--使用设置本地JDBC对象抽取只要不是oracle9i则可以将OracleLobHandler改为DefaultLobHandler而且也不需要-p:nativeJdbcExtractor-ref="nativeJdbcExtractor"->-->
    lazy-init="true" p:nativeJdbcExtractor-ref="nativeJdbcExtractor"/>
    设置为lazy=true是因为nativeJdbcExtractor需要通过运行期的反射机制获取底层的jdbc对象,所以需要避免让Spring容器启动时就实例化这两个Bean
    LobHandler需要访问本地Jdbc对象,因此需要通过一个NativeJdbcExtractor Bean来完成任务
    2、以块数据方式获取Lob数据
    用户可以直接以数据块的方式读取Lob数据:以String读取Clob字段的数据,而以byte[]读取Blob字段的数据。
    public List<ViewPoint> getImgFiles(final int spaceId) {
    String sql = " SELECT point_id,img_file FROM t_view_point where point_id =? and img_file is not null ";
    return jdbcTemplate.query(sql, new Object[]{spaceId},
    new RowMapper<ViewPoint>() {
    public ViewPoint mapRow(ResultSet rs, int rowNum)throws SQLException {
    int pointId = rs.getInt(1);
    byte[] attach = lobHandler.getBlobAsBytes(rs, 2);//以二进制的方式获取Blob数据
    ViewPoint viewPoint = new ViewPoint();
    viewPoint.setPointId(pointId);
    viewPoint.setImgFile(attach);
    return viewPoint;
    }
    });
    }
    通过JdbcTemplate的List<T>query(String sql;Object[]args,RowMapper rowMapper)接口处理行数据的映射,在RowMapper回调的mapRow()接口方法中,通过LobHandler以byte[]获取Blob字段的数据
    3、以流数据方式读取Lob数据
    由于Lob数据的体积可能很大,如果直接以块的方式操作Lob数据,需要消耗大量的内存,直接影响到程序的整体运行,对于体积很大的Lob数据,可以使用流的方式进行访问,减少内存的占用,JdbcTemplate为此提供了一个Object query(String sql,Object[]args,ResultSetExtractor rse)fangfa
    ResultSetExtractor接口拥有一个处理流数据的抽象类org.springframework.jdbc.core.supportAbstractLobStreamingResultS,可以通过扩展此类用流的方式操作Lob字段的数据
    public void getImgFile(final int pointId, final OutputStream os) {//用于接收Lob数据的输出流
    String sql = " SELECT img_file FROM t_view_point where point_id =? ";
    jdbcTemplate.query(sql, new Object[]{pointId},
    new AbstractLobStreamingResultSetExtractor() {//匿名内部类
    protected void handleNoRowFound() throws LobRetrievalFailureException {//处理未找到数据行的情况
    System.out.println("Not Found result!");
    }

    public void streamData(ResultSet rs) throws SQLException, IOException {//以流的方式处理Lob字段
    InputStream is = lobHandler.getBlobAsBinaryStream(rs, 1);
    if (is != null) {
    FileCopyUtils.copy(is, os);
    }
    }
    }
    );
    }
    通过扩展 AbstractLobStreamingResultSetExtractor抽象类在streamData(ResultSet rs)方法中以流的方式读取Lob字段数据。这里又利用了Spring的工具类FileCopyUtils,将输入流的数据复制到输出流中。在getImgFile方法中通过入参OutputStream接收Lob的数据
    四、其他类型的JdbcTemplate
    除了标准的JdbcTemplate之外,Spring还提供了两个好用的JDBC模板类,他们分别是NamedParameterJdbcTemplate和SimpleJdbcTemplate.
    1、NamedParameterJdbcTemplate
    在低版本的Spring中,用户只能使用?占位符声明参数,并使用索引号绑定参数,使用这种方法绑定参数时,必须足够小心,以确保正确匹配。
    @Repository
    public class ViewSpaceDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    public void addViewSpaceByNamedParams(final ViewSpace viewSpace) {
    final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(:spaceName,:description,:address)";//定义参数源
    SqlParameterSource sps = new BeanPropertySqlParameterSource(viewSpace);//定义命名参数
    namedParameterJdbcTemplate.update(sql, sps);//使用模板方法
    }
    }
    需要在Spring的配置文件中添加
    <bean id="namedParamJdbcTemplate"
    class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    <constructor-arg ref="dataSource"/>
    </bean>
    在SQL语句中,声明命名参数的格式是:paramName,在这个示例中使用BeanPropertySqlParameterSource提供参数源,他接受一个JavaBean作为构造函数的入参,和标准的JdbcTemplate一样,NamedParameterJdbcTemplate提供了很多的数据访问方法,这些方法大多都拥有一个SqlParameterSource入参,用来提供参数源
    上述中的spaceName等都是和Sql语句中命名参数匹配,如果数据表记录没有对应的领域对象
    MapSqlParameterSource sps=new MapSqlParameterSource().addValue("spaceName",viewSpace.getSpaceName()).addValue("address",viewSpace.getAddress());
    五、使用OO方式访问数据库
    org.springframework.jdbc.object包下的类允许用户以更加面向对象的方式访问数据库,用户通常也可以直接使用JdbcTemplate完成类似的操作,相对于把一个查询操作封装成一个类而言,我们直接调用JdbcTemplate方法更加简洁,更容易理解。
    1、使用MappingSqlQuery查询数据
    SqlQuery是一个可重用,线程安全的类,它封装了一个SQL查询。用户很少需要直接使用SqlQuery,因为其子类MappingSqlQuery作为一个更加易用的实现类能够将结果集中的行映射为Java对象,SqlQuery还有两个扩展类,分别是MappingSqlQueryWithParameters和UpdateableSqlQuery
    @Repository
    public class ViewSpaceOODao {
    @Autowired
    private DataSource dataSource;

    private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量
    @PostConstruct
    public void init() {
    this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象
    this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource);
    this.viewPointNum = new GetViewPointNum(this.dataSource);
    this.viewSpaceNumCount = new SqlFunction<Integer>(dataSource, "SELECT COUNT(*) FROM t_view_space");
    this.viewSpaceNumCount.compile();
    }
    public ViewSpace getViewSpace(int spaceId) {
    return viewSpaceQuery.findObject(spaceId); //③执行查询并返回结果
    }

    //④定义MappingSqlQuery
    private class ViewSpaceQuery extends MappingSqlQuery<ViewSpace> {
    public ViewSpaceQuery(DataSource ds) {//⑤定义查询语句并预编译
    super(ds, "SELECT space_id,space_name, description FROM t_view_space WHERE space_id=?");
    declareParameter(new SqlParameter(Types.INTEGER));
    compile();//⑤-1不能忘记这行编译语句,否则会发生错误
    }

    public ViewSpace mapRow(ResultSet rs, int rownum) throws SQLException {//⑥
    ViewSpace viewSpace = new ViewSpace();
    viewSpace.setSpaceId(rs.getInt("space_id"));
    viewSpace.setSpaceName(rs.getString("space_name"));
    viewSpace.setDescription(rs.getString("description"));
    return viewSpace;
    }
    }
    使用MappingSqlQuery一般分为以下3个步骤:
    1)定义子类,在子类中声明SQL语句并定义行数据映射逻辑
    2)声明子类来的变量并实例化该类
    3)使用MappingSqlQuery的方法执行数据查询操作
    2、使用SqlUpdate更新数据
    @Repository
    public class ViewSpaceOODao {
    @Autowired
    private DataSource dataSource;

    private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量

    private ViewSpaceInsert viewSpaceInsert;
    @PostConstruct
    public void init() {
    this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象
    this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource);
    }
    //①新增Forum对象
    public void addViewSpace(ViewSpace viewSpace) {
    viewSpaceInsert.insert(viewSpace);
    }

    //②扩展SqlUpdate定义子类
    private class ViewSpaceInsert extends SqlUpdate {
    public ViewSpaceInsert(DataSource ds) {//③定义SQL语句并预编译
    super(ds, "INSERT INTO t_view_space(space_name, description) VALUES(:spaceName,:description)");
    declareParameter(new SqlParameter("spaceName", Types.VARCHAR));
    declareParameter(new SqlParameter("description", Types.VARCHAR));
    compile();
    }
    }
    3、使用StoredProcedure执行存储过程
    @Repository
    public class ViewSpaceOODao {
    @Autowired
    private DataSource dataSource;

    private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量

    private ViewSpaceInsert viewSpaceInsert;

    private GetViewPointNum viewPointNum;
    @PostConstruct
    public void init() {
    this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象
    this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource);
    this.viewPointNum = new GetViewPointNum(this.dataSource);
    }
    public int getViewPointNum(int userId) {
    return viewPointNum.getViewPointNum(userId);
    }

    //①扩展StoredProcedure
    private class GetViewPointNum extends StoredProcedure {
    private static final String SQL = "P_GET_VIEW_POINT_NUM";//②定义存储过程名

    public GetViewPointNum(DataSource ds) {
    setDataSource(ds);
    setSql(SQL);
    //③声明入参
    declareParameter(new SqlParameter("spaceId", Types.INTEGER));
    //④声明出参
    declareParameter(new SqlOutParameter("outNum", Types.INTEGER));
    compile();
    }
    public int getViewPointNum(int userId) {//⑤执行存储过程并返回结果
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("userId", userId);
    Map<String, Object> outMap = execute(map);
    return (Integer) outMap.get("outNum");
    }
    }
    }
    通过StoredProcedure执行存储过程SQL语句只需指定存储过程的名,不通过占位符声明入参和出参。而通过declareParameter()方法声明入参合成出参。
    4、SqlFunction类
    SqlFunction操作类封装了一个SQL函数包装器,该包装器适用于查询并返回一个单行结果集的访问操作。默认返回的是一个int值,不过更推荐使用JdbcTemplate中的queryForXxx()方法返回单值数据
    @Repository
    public class ViewSpaceOODao {
    @Autowired
    private DataSource dataSource;

    private SqlFunction<Integer> viewSpaceNumCount;

    @PostConstruct
    public void init() {
    this.viewSpaceNumCount = new SqlFunction<Integer>(dataSource, "SELECT COUNT(*) FROM t_view_space");
    this.viewSpaceNumCount.compile();
    }
    public int getViewSpaceNum() {
    return viewSpaceNumCount.run();
    }
    }
  • 相关阅读:
    Linux下设置svn开机自启动
    LNMP 如何安装mongodb ----lnmp一键安装包之后
    MySQL表类型MyISAM/InnoDB的区别(解决事务不回滚的问题)
    PHP处理MySQL事务代码
    php redis 秒杀demo
    PHP5.6版本安装redis扩展
    Jzoj5662 尺树寸泓
    Jzoj3351 神牛养成计划2
    Jzoj5622 table
    Jzoj5608 Subset
  • 原文地址:https://www.cnblogs.com/dream-to-pku/p/5794267.html
Copyright © 2011-2022 走看看