mapengpeng1999@163.com Spring对JDBC的支持JdbcTemplate,使用具名参数NamedParameterJdbcTemplate,Junit

Spring对JDBC的支持

JDBC是连接数据库的标准,DBUtil或JdbcTemplete工具都是在原生JDBC基础上封装而来,
一切进行数据操作的工具或框架都是JDBC基础上封装而来。
在以后的项目开发中,我们一般不会使用原生的JDBC进行数据库操作,也不会使用DBUtil这种类似的工具,
而我们今天讲解的JdbcTemplate也属于工具,不是框架。我们讲解JdbcTemplate目的就是为了讲解后面的声明式事务,我们以后的开发肯定使用框架开发,目前主流的ORM【Object relation mapping】对象关系映射框架
就是MyBatis(半自动化框架),往前就是Hibernate(全自动化框架)。
事务处理是放在业务层,数据增删改查操作是在数据持久化访问层。

JdbcTemplate

为了使JDBC的操作更加简洁,易于使用,Spring在原生的JDBC的API上定义了一个抽象层,
从而建立了一个JDBC的存取的工具。这个工具是作为SpringJDBC的核心,创建的一系列增删改查操作模板,
每个模板方法都能够控制整个过程,并允许覆盖过程中的特定任务,
以这种方式可以在尽可能保留灵活性的情况下,将数据库的增删改查的工作量降到最低。
JDBCTemplate的操作步骤:

1.加入jar包

c3p0-0.9.1.2.jar
commons-logging-1.1.3.jar
mysql-connector-java-5.1.37-bin.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
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar

2.配置数据库连接信息:conf类路径配置文件下的db.properties文件(普通的file文件)

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/buybook
user=root
password=3306
maxSize=10 //连接池最大值
initSize=5  //连接池初始化值

3.配置Spring的xml文件

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- 导入外部的属性文件 -->
	<context:property-placeholder location="classpath:db.properties"/>
	<!-- 配置连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		//不是springEL表达式,是jspEL表达式
		<property name="driverClass" value="${driver}"></property>
		<property name="jdbcUrl" value="${url}"></property>
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="maxPoolSize" value="${maxSize}"></property>
		<property name="initialPoolSize" value="${initSize}"></property>
	</bean>
	<!-- 配置JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

4.编写测试类

package com.wanbangee.junit;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class Test {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = act.getBean(JdbcTemplate.class);
String sql = "insert into account(acc_name,acc_pass,acc_balance) values(?,?,?),(?,?,?)";
	int x = jdbcTemplate.update(sql, "aa","123456",50,"bb","223456",500);
	//执行增删改操作,并传递sql中?号占位符的值,返回值表示影响的数据笔数
	System.out.println(x);
}
}

JUnit Test Case

使用Junit,和new类一样new个JUnit Test Case,并命名(和类名命名一样),勾上setUp()和tearDown()

package com.wanbangee.junit;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JunitDemo01 {
	//在每个@Test注解的测试方法执行之前都会执行setUp方法
	@Before
	public void setUp() throws Exception {
		System.out.println("before,在所有的测试方法执行之前执行");
	}
	//每个@Test注解的测试方法执行之后都会执行tearDown方法
	@After
	public void tearDown() throws Exception {
		System.out.println("after,在所有的测试方法执行之后执行");
	}
	//在此页面右击此处@Test的方法,run as采用JUnit Test方式运行,运行结果有一长串绿色表示运行成功
	@Test
	public void test() {
		System.out.println("Hello Junit,测试方法");
	}
	//运行结果有一长串红色表示运行不成功,有异常或错误
	@Test
	public void test01() {
		System.out.println(1/0);
		System.out.println("Hello test01,测试方法");
	}
}
Junit 是标准的单元测试工具
使用Junit(添加Junit步骤:右击项目名,点properties,java build path,添加Libraries,Add Library,
选最新的JUnit4版本)新建个包,在包下new个JUnit Test Case,随便取个名字(和类名命名一样),
勾上setUp()和tearDown()
package com.wanbangee.junit;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateTest {

	ConfigurableApplicationContext act = null;
	JdbcTemplate jdbcTemplate = null;
	
	@Before
	public void setUp() throws Exception {
		act = new ClassPathXmlApplicationContext("applicationContext.xml");
		jdbcTemplate = act.getBean(JdbcTemplate.class);
	}

	@After
	public void tearDown() throws Exception {
		act.close();
	}
//update方法执行增删改操作,并传递sql中?号占位符的值,返回值为int型,表示影响的数据笔数。
	@Test
	public void testDelete() {
		String sql = "delete from account where acc_id = ?";
		jdbcTemplate.update(sql, 21);
	}
	@Test
	public void testUpdate() {
		String sql = "update account set acc_name = ? where acc_id = ?";
		jdbcTemplate.update(sql, "张三丰",19);
	}
	@Test
	public void testInsert() {
		String sql = "insert into account(acc_name,acc_pass,acc_balance) values(?,?,?)";
		jdbcTemplate.update(sql, "张三丰","123456",500);
	}
	//查询单笔数据
	@Test
	public void testQueryOneLine() {
		String sql = "select acc_id,acc_name,acc_pass,acc_balance,acc_pic from account where acc_id = ?";
		RowMapper<Account> rowMapper = null; 
		//会将查询结果集的行映射成实体类的一个对象
		rowMapper = new BeanPropertyRowMapper<>(Account.class);
		//会根据查询的列名和实体类Javabean风格的属性名自动匹配,列名如果带下划线,则会匹配对应驼峰的属性
		Account account = jdbcTemplate.queryForObject(sql, rowMapper, 11);//11表示id为11的
		System.out.println(account);
	}
	//查询多笔数据
	@Test
	public void testQueryAnyLine() {
		String sql = "select acc_id,acc_name,acc_pass,acc_balance,acc_pic from account";
		RowMapper<Account> rowMapper = null; 
		//会将查询结果集的行映射成实体类的一个对象
		rowMapper = new BeanPropertyRowMapper<>(Account.class);
		//会根据查询的列名和实体类Javabean风格的属性名自动匹配,列名如果带下划线,则会匹配对应驼峰的属性
		List<Account> accounts = jdbcTemplate.query(sql, rowMapper);
		System.out.println(accounts);
	}
	//查询单行单列数据SELECT COUNT(acc_id) FROM account;
	@Test
	public void testQueryOneData() {
		String sql = "SELECT COUNT(acc_id) FROM account where acc_id > ?";
		int x = jdbcTemplate.queryForObject(sql, Integer.class, 10);
		System.out.println(x);
	}	
	//查询多笔数据没有对应的实体类 SELECT MAX(acc_balance) max_b,MIN(acc_balance) min_b FROM account;
	@Test
	public void testQueryForMap() {
		String sql = "SELECT MAX(acc_balance) max_b,MIN(acc_balance) min_b FROM account";
		Map<String,Object> map = jdbcTemplate.queryForMap(sql);
		
		Set<String> keys = map.keySet();
		for (String key : keys) {
			System.out.println(key + "---------" + map.get(key));
		}
	}
}

JdbcTemplate在项目中的使用

所有的项目开发中,后台开发都是遵循三层架构:
- 控制层
- 业务层
- 数据访问层【持久化层】
三层架构中,控制层调用业务层,业务层调用持久化层(数据访问层DAO),持久化层使用JDBC或者由JDBC封装而来的工具或者框架来完成数据库的增删改查的实际操作。那么我们的JdbcTemplate也就意味着实在持久化层使用。

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/buybook
user=root
password=3306
maxSize=10 
initSize=5  

<?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:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置连接池  -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${driver}"></property>
		<property name="jdbcUrl" value="${url}"></property>
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="maxPoolSize" value="${maxSize}"></property>
		<property name="initialPoolSize" value="${initSize}"></property>
	</bean>
<!-- 配置JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.wanbangee"></context:component-scan>
</beans>
package com.wanbangee.entities;
public class Account {
	private Integer accId;
	private String accName;
	private String accPass;
	private Double accBalance;
	private String accPic;
	public String getAccPic() {
		return accPic;
	}
	public void setAccPic(String accPic) {
		this.accPic = accPic;
	}
	public Integer getAccId() {
		return accId;
	}
	public void setAccId(Integer accId) {
		this.accId = accId;
	}
	public String getAccName() {
		return accName;
	}
	public void setAccName(String accName) {
		this.accName = accName;
	}
	public String getAccPass() {
		return accPass;
	}
	public void setAccPass(String accPass) {
		this.accPass = accPass;
	}
	public Double getAccBalance() {
		return accBalance;
	}
	public void setAccBalance(Double accBalance) {
		this.accBalance = accBalance;
	}
	@Override
	public String toString() {
		return "Account [accId=" + accId + ", accName=" + accName + ", accPass=" + accPass + ", accBalance="+ accBalance + ", accPic=" + accPic + "]";
	}
}


package com.wanbangee.dao;
import java.util.List;
import com.wanbangee.entities.Account;
public interface AccountDao {
public List<Account> selectAllAccount();
}


package com.wanbangee.dao.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entities.Account;
@Repository
public class AccountDaoImp implements AccountDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	@Override
	public List<Account> selectAllAccount() {
		List<Account> accounts = null;
		try {
		String sql = "select acc_id,acc_name,acc_pass,acc_balance,acc_pic from account";
			RowMapper<Account> rowMapper = null;//会将查询结果集的行映射成实体类的一个对象
			rowMapper = new BeanPropertyRowMapper<>(Account.class);
		//会根据查询的列名和实体类Javabean风格的属性名自动匹配,列名如果带下划线,则会匹配对应驼峰的属性
			 accounts = jdbcTemplate.query(sql, rowMapper);
			 return accounts;
		} catch (Exception e) {
			e.printStackTrace();
			return null;//出现异常返回null
		}
	}
}


package com.wanbangee.service;
import java.util.List;
import com.wanbangee.entities.Account;
public interface AccountService {
public List<Account> selectAllAccount();
}


package com.wanbangee.service.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entities.Account;
import com.wanbangee.service.AccountService;
@Service
public class AccountServiceImp implements AccountService {
@Autowired
private AccountDao accountDao;
	@Override
	public List<Account> selectAllAccount() {
		return accountDao.selectAllAccount();
	}
}


package com.wanbangee.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.wanbangee.entities.Account;
import com.wanbangee.service.AccountService;
@Controller
public class AccountController {
@Autowired
private AccountService accountService;
public Map<String,Object> selectAllAccount(){
	List<Account> accounts = accountService.selectAllAccount();
	Map<String,Object> map = new HashMap<>();
	if(accounts == null) {
		map.put("code", 1003);
		map.put("message", "执行失败");
	}else {
		if(accounts.isEmpty()) {
			map.put("code", 1002);
			map.put("message", "查无此数");
		}else {
			map.put("code", 1001);
			map.put("message", "执行成功");
			map.put("accounts", accounts);
		}
	}
	return map;
}
}


package com.wanbangee.test;
import static org.junit.Assert.*;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.wanbangee.controller.AccountController;

public class TestMVCJUnit {
	ConfigurableApplicationContext act = null;//成员变量默认为null的不写也行
	AccountController accountController = null;
	
	@Before
	public void setUp() throws Exception {
		act = new ClassPathXmlApplicationContext("applicationContext.xml");
		accountController = act.getBean(AccountController.class);
	}

	@After
	public void tearDown() throws Exception {
		act.close();
	}

	@Test
	public void test() {
		Map<String,Object> map = accountController.selectAllAccount();
		//将所有的键封装进set集合,
		Set<String> keys = map.keySet();
		for (String key : keys) {
			System.out.println(key);
			System.out.println(map.get(key));
		}
	}
}
使用具名参数NamedParameterJdbcTemplate
在经典的JDBC的操作做那个,SQL参数是使用占位符?表示,并且受到位置的限制,定位参数的问题就存在于,
如果参数过多,或者参数的位置发生变化。这个时候我们就可以对参数进行绑定, 绑定参数指的是给参数起一个别名,
而后通过别名给参数设置值,这种操作形式叫做具名参数,在sql中 用 ‘:别名’的方式 替换‘?’号占位符。
具名参数使用NamedParameterJdbcTemplate进行操作,
且NamedParameterJdbcTemplate是JdbcTemplate的一个子类。
使用NamedParameterJdbcTemplate步骤:
1.编写Spring的配置文件
	<!-- 导入外部的属性文件 -->
	<context:property-placeholder location="classpath:db.properties"/>
	<!-- 配置连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="${url}"></property>
		<property name="driverClass" value="${driver}"></property>
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="maxPoolSize" value="${maxSize}"></property>
		<property name="initialPoolSize" value="${initSize}"></property>
	</bean>
	
	<!-- 配置JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
<!-- 具名参数的jdbcTemplate -->
	<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
		<constructor-arg ref="dataSource"></constructor-arg> 
	</bean>
	<!--property属性注入,set注入,调用无参构造器, constructor-arg构造注入,调有参构造器
	具名参数类NamedParameterJdbcTemplate中没有无参构造器,只有有参构造器-->
	</bean>
Junit 是标准的单元测试工具
private ApplicationContext act = null;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;
	@Before
	public void setUp() throws Exception {
		//每个@Test注解的测试方法执行之前都会执行setUp方法
		act = new ClassPathXmlApplicationContext("applicationContext.xml");
		namedParameterJdbcTemplate = act.getBean(NamedParameterJdbcTemplate.class);
	}

	@After
	public void tearDown() throws Exception {
		//每个@Test注解的测试方法执行之后都会执行tearDown方法
	}

//给参数起别名,参数别名不能一样。用Map集合来封装参数,参数以键值对形式传入Map对象,参数名与key要一一对应。
	@Test
	public void testInsert() {
		String sql = "insert into account(acc_name,acc_pass,acc_balance) values(:name,:pass,:balance)"; //sql中使用 :参数别名 替代 ?
		Map<String,Object> paramMap = new HashMap<>();
		paramMap.put("name", "小马");//Map键值对为参数设置值
		paramMap.put("pass", "123");
		paramMap.put("balance", 4000);
		namedparameterJdbctemplate.update(sql, paramMap);//把参数放入map键值对中,把map对象传入
	}

使用具名参数的好处在于,多个参数我们不需要再按照顺序设置,直接使用参数名即可,便于维护,

缺点就是比较麻烦,在实际开发中,参数肯定是通过具名参数设置的。

总结

JdbcTemplate充其量就是一个JDBC的小工具,和ORM框架是没有办法相比的;
JdbcTemplate在使用过程中,比传统原生的JDBC的操作或者是DBUtil更加好用,更加简洁;
JdbcTemplate可以在sql中使用占位符,NamedParameterJdbcTemplate可以使用具名参数;
JdbcTemplate在开发中的使用过程一定要掌握;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值