我是靠谱客的博主 等待向日葵,最近开发中收集的这篇文章主要介绍SpringJDBC,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

SpringJDBC是对原生JDBC的一个封装,它不是一个ORM框架,但是对于一些小项目来说,它的所提供的功能就已经卓卓有余了,而且对于一些比价复杂的SQL 原声的JDBC还是有它一定的优势,所以今天我就将SpringJDBC的知识写一下。

首先Spring为各种持久化技术提供模板类,这样做有两点,第一点方面操作,第二点你让hibernate的session和connection等这些线程不安全的类 变成了线程安全了(因为使用了ThreadLocal类),这些就不在这里讨论了,如果对这方面有兴趣可以看一下《Spring 3.X企业应用开发实战》。

使用SpringJDBC的前提地下要配置数据源,下面我就列出数据源的完整配置,当然在配置文件中不需要将所有属性都设置上。

以下就是datasource.properties 的属性配置(这使用的是BasicDataSource 数据源,在Spring ORM 章节 我会采用 C3P0的 数据源 会有更加详细的C3P0配置):

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/springreview
username=root
password=tonyyan

#连接池创建的连接的默认auto-commit状态(默认值:true)
defalutAutoCommit=true

#连接池创建的连接的默认的read-only状态。如果没有设置则setReadOnly方法将不会被调用 (默认值:驱动默认)
defaultReadOnly=false

#连接池创建的连接的默认的TransactionIsolation状态,可选值如下(默认值:驱动默认):
#NONE
READ_COMMITTED READ_UNCOMMITTED REPEATABLE_READ SERIZLIZABLE
defaultTransactionIsolation=READ_COMMITTED

#初始化连接,连接池启动时创建的初始化连接数量(默认值:0)
initialSize=0

#最大活动连接,连接池启动时创建的初始化连接数量(默认值:8)
maxActive=8

#最大空闲连接,连接池中容许保持空闲状态的最大连接数,超过的空闲连接将被释放,如果设置为负数表示不限制(默认值:8)
maxIdle=8

#最小空闲连接,连接池中容许保持空闲状态的最小连接数,超过的空闲连接将被释放,如果设置为负数表示不限制(默认值:0)
minIdle=0

#最大等待事件,当没有可用连接时,连接池等待连接被归还的最大时间(毫秒为单位),超过事件则抛出异常,如果设置-1表示无线等待(默认值:无限)
maxWait=1500

#SQL查询语句。用于连接有消息检查,必须放回至少一行的数据MYSQL中可以设置select 1 oracle可以设置select 1 from dual
validationQuery=select 1

#指明是否在从连接池中取出连接并连接前前进行检查,如果检查失败,则从连接池删除该连接并尝试取出另外一个新连接(默认值:TRUE) 必须设置validationQuery
testOnBorrow=false

#指明是否在连接使用完毕后将连接归还给连接池是进行有效性检查,如果失败,则从连接池中删除该连接(默认值:FALSE) 必须设置validationQuery
testOnReturn=false

#指明连接是否被空闲回收器进行检查,如果检查失败,则连接将从池中去除(默认值:FALSE) 必须设置validationQuery
testWhileIdle=true

#空闲连接回收器线程运行的周期(毫秒为单位)如果设置非整数,则不运行。(默认值:-1) 必须设置validationQuery
timeBetweenEvictionRunsMillis=3600000

#每次空闲连接回收器线程运行时检查的连接数量
numTestsPerEvictionRun=3

#连接在可被空闲接连回收器收前已经在池中空闲的时间(毫秒为单位)(默认值:1000*60*30)
minEvictableIdleTimeMillis=1800000

#开启池的prepared statement 池功能,设置为true CallableStatement 和 PreparedStatemen 都会被缓存起来(默认值:FALSE)
poolPreparedStatements=false

#PreparedStatement池能够同时分配的打开的statements的最大数量,如果设置为0表示不限制(默认值:无限)
maxOpenPreparedStatements=0

#标记是否删除泄露的连接,如果为true则如果可能存在泄露的连接将会被主动清除,
#这个机制在(getNumIdle()<2 and (getNumActive() > getMaxActive()-3))条件下触发。
removeAbandoned=false

#泄露的连接可以被回收的超时时间(秒为单位)(默认值:300)
removeAbandonedTimeout=72000

#标记当Statement或者连接被泄露时是否打印程序的stack traces日志。
#被泄露的statement和连接的日志添加在每个连接打开或者生成的statement,因为需要生成stack trace
logAbandoned=false

以下是Spring的配置文件:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd">



<context:property-placeholder location="datasource.properties"/>


<context:component-scan base-package="com.maxfunner"/>


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="${driverClassName}"/>

<property name="url" value="${url}"/>

<property name="username" value="${username}"/>

<property name="password" value="${password}"/>

</bean>


<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"/>


<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

p:dataSource-ref="dataSource"/>


<aop:config>

<aop:pointcut id="allServices" expression="within(com.maxfunner.service..*)" />

<aop:advisor advice-ref="txAdvice" pointcut-ref="allServices" />

</aop:config>


<tx:advice id="txAdvice" transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="*" read-only="false" isolation="READ_COMMITTED" />

</tx:attributes>

</tx:advice>


</beans>

当然我都配置了Spring的声明式事务,将service所有类都进行声明式事务的织入。

以下将Spring的模板类和所有事物管理器(transaction manager)列出:


Template:

JDBC ---> org.springframework.jdbc.core.JdbcTemplate

Hibernate --->org.springframework.orm.hibernate5.HibernateTemplate (这里是hibernate5的template spring支持从hibernate3开始的所有template)

mybatis在mybatis的包中提供,其他我没有用过的就不写了。。。


PlatformTransactionManager 的实现类如下:

org.springframework.orm.hibernate5.HibernateTransactionManager  (这里是hibernate5的template spring支持从hibernate3开始的所有TransactionManager)

org.springframework.jdbc.datasource.DataSourceTransactionManager (SpringJDBC和mybatis使用这个)

其他jdo 和 JTA 我就不写了。。。


以下是一个使用SpringJDBC 创建表插入数据的实例:

@Repository
public class UserDao {
@Autowired

private JdbcTemplate template;


public JdbcTemplate getTemplate() {
return template;

}
public void setTemplate(JdbcTemplate template) {
this.template = template;

}
public void initUserTable(){
String createTableSql = "create table t_user(user_id int primary key auto_increment,username varchar(100),pwd varchar(100))";


String dropOldTableSQL = "drop table if exists t_user";



//使用JdbcTemplate执行删除原表

template.execute(dropOldTableSQL);


//使用JdbcTemplate创建表

template.execute(createTableSql);


//使用GeneratedKeyHolder获得新插入数据的主键

KeyHolder keyHolder = new GeneratedKeyHolder();


final String insertUserSQL = "insert into t_user(username,pwd) VALUES (?,?)";


final User adminUser = new User("Admin","adminPwd");


//使用JdbcTemplate去更新数据

template.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
//通过connection获得PreparedStatement 同时指定需要返回主键RETURN_GENERATED_KEYS

PreparedStatement statement = connection.prepareStatement(insertUserSQL, Statement.RETURN_GENERATED_KEYS);

//传入参数

statement.setString(1,adminUser.getUsername());

statement.setString(2,adminUser.getPwd());

return statement;

}
},keyHolder);



//输出保存插入数据的主键到对象当中

adminUser.setUserId(keyHolder.getKey().intValue());


System.out.println("adminUser ->>>>>> " + adminUser);


//需要批量处理的List

final List<User> userList = new ArrayList<User>();

userList.add(new User("TONY","TONYPWD"));

userList.add(new User("asd","TONYPWD"));

userList.add(new User("sds","TONYPWD"));

userList.add(new User("fvcx","TONYPWD"));

userList.add(new User("xwd","TONYPWD"));

userList.add(new User("dfsd","TONYPWD"));

userList.add(new User("cew","TONYPWD"));

userList.add(new User("adfd","TONYPWD"));

userList.add(new User("sdfwe","TONYPWD"));



//使用JdbcTemplate的批量插入

template.batchUpdate(insertUserSQL, new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
preparedStatement.setString(1,userList.get(i).getUsername());

preparedStatement.setString(2,userList.get(i).getPwd());

}
public int getBatchSize() {
return userList.size();

}
});

}
}

使用查询数据之RowMapper处理数据集实例:

public List<User> getAllUser(){
String sql = "select user_id,username,pwd from t_user where user_id between ? and ?";

List<User> userList = template.query(sql, new Object[]{1, 10}, new RowMapper<User>() {
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();

user.setUserId(resultSet.getInt(1));

user.setUsername(resultSet.getString(2));

user.setPwd(resultSet.getString(3));

return user;

}
});

return userList;
}

使用查询数据之RowCallbackHandler处理数据集:

public List<User> getAllUser() {
String sql = "select user_id,username,pwd from t_user where user_id between ? and ?";


final List<User> userList = new ArrayList<User>();


template.query(sql, new Object[]{1, 10}, new RowCallbackHandler() {
public void processRow(ResultSet resultSet) throws SQLException {
User user = new User();

user.setUserId(resultSet.getInt(1));

user.setUsername(resultSet.getString(2));

user.setPwd(resultSet.getString(3));

userList.add(user);

}
});


return userList;
}

使用JdbcTemplate查询单条数据:

public int getUserCount() {
String countSQL = "select count(*) from t_user";

return this.template.queryForObject(countSQL, new RowMapper<Integer>() {
public Integer mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getInt(1);

}
});
}

使用SpringTemplate 调用存储过程:


以下是我在MySQL创建的存储过程

delimiter //
create procedure P_USER_NAME(IN in_user_id int , OUT out_name varchar(100))
begin
select username into out_name  from t_user where user_id = in_user_id;
end


使用SpringTemplate进行调用:

public String getUserNameById(final int userId){
String sql = "{call P_USER_NAME(?,?)}";

String username = this.template.execute(sql, new CallableStatementCallback<String>() {
public String doInCallableStatement(CallableStatement callableStatement) throws SQLException, DataAccessException {
callableStatement.setInt(1,userId);

callableStatement.registerOutParameter(2,Types.VARCHAR);

callableStatement.execute();

return callableStatement.getString(2);

}
});

return username;
}

当然我们可以返回一个ResultSet行集数据 但是我们返回的是Spring提供的SqlRowSet,用法基本上和resultSet差不多,但是需要注意的是resultSet是连接性行集,就是说是在连接过程中使用的行集合,但是Spring提供的是SqlRowSet是非连接性行集,所以不会像resultSet一样采取分批返回数据,sqlRowSet会一次性放回所有的行集(fetchsize)所以需要特别注意,如果一般小心就会导致JVM的内存销毁压力山大。以下是关于SqlRowSet的用法:

public SqlRowSet getAllUserRowSet(){
String sql = "select user_id,username,pwd from t_user ";

SqlRowSet rowSet = this.template.queryForRowSet(sql);

while (rowSet.next()) {
System.out.println("user_id : " + rowSet.getInt(1) +
" , name : " + rowSet.getString(2) +
" , pwd : " + rowSet.getString(3));

}
return rowSet
}

我们还可以使用另外一种JDBCTemplate去完成操作,NamedParameterJdbcTemplate。

使用NamedParameterJdbcTemplate 可以不使用?这种占位符,可以对占位符进行命名,减少出错机会。而且还可以BeanPropertySqlParameterSource将目标类的属性名与参数名进行对应,从而可以自动传参数,看看以下例子:

public void insertUser(User user){
String sql = "insert into t_user(username,pwd) values(:username,:pwd)";

SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(user);

namedParameterJdbcTemplate.update(sql,parameterSource);
}

其中User类有三个属性 userId,username,pwd 所以BeanPropertySqlParameterSource自动取对象中的username 和 pwd值,但是如果要使用NamedParameterJdbcTemplate也需要在配置文件进行配置,配置如下:

<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">

<const

如果不使用BeanPropertySqlParameterSource还可以用以下方法进行相同的操作:

public void insertUser(User user){
String sql = "insert into t_user(username,pwd) values(:username,:pwd)";

Map<String,Object> params = new HashMap<String, Object>();

params.put("username",user.getUsername());

params.put("pwd",user.getPwd());

namedParameterJdbcTemplate.update(sql,params);
}
可以看见我只使用了一个Map作为一个参数传入了 template的update方法当中,当然也可以使用MqlSqlParameterSource这个跟直接使用Map差别不大。


以OO方式访问数据库,就不再这里说了,因为对于我本人来说以上几种才是我用的比较多的方式,如果兴趣的读者可以参考《Spring 3.X企业应用开发实战》(近期看见出了4.x)我个人觉得这本书把spring的很多东西都说的很详细,如果有其他读者觉得有其他好书也可以在评论中评论跟我分享。


最后

以上就是等待向日葵为你收集整理的SpringJDBC的全部内容,希望文章能够帮你解决SpringJDBC所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部