1 AOP
Spring 是解决实际开发中的一些问题,而 AOP 解决 OOP 中遇到的一些问题.是 OOP 的延续和扩展.
使用面向对象编程 ( OOP )有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。
1.1 为什么学习 AOP
在不修改源码的情况下,对程序进行增强
AOP 可以进行权限校验,日志记录,性能监控,事务控制
1.2 Spring 的 AOP 的由来
AOP 最早由 AOP 联盟的组织提出的,制定了一套规范.Spring 将 AOP 思想引入到框架中,必须遵守 AOP 联盟 的规范.
1.3底层实现
AOP依赖于IOC来实现,在AOP中,使用一个代理类来包装目标类,在代理类中拦截目标类的方法执行并织入辅助功能。在Spring容器启动时,创建代理类bean替代目标类注册到IOC中,从而在应用代码中注入的目标类实例其实是目标类对应的代理类的实例,即使用AOP处理目标类生成的代理类。
代理机制:
Spring 的 AOP 的底层用到两种代理机制:
JDK 的动态代理 :针对实现了接口的类产生代理.
Cglib 的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类的子类对象.
1.4 动态代理
Java中提供的动态代理,增强一个类的方法
package com.tledu.service.impl;
import lombok.Getter;
import lombok.Setter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogInterceptor implements InvocationHandler {
/**
* 被代理的对象
*/
@Getter
@Setter
private Object target;
private void before(Method method) {
System.out.println(method.getName()+"调用之前");
}
private void after(Method method) {
System.out.println(method.getName()+"调用之后");
}
/**
* @param proxy 代理的对象
* @param method 代理的方法
* @param args 方法的参数
* @return 方法的返回值
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置操作
before(method);
// 通过被代理对象调用真正需要执行的方法
Object res = method.invoke(target, args);
// 后置操作
after(method);
return res;
}
}
测试
@Test
public void proxy() {
// 创建真实的对象
IUserDao userDao = new UserDaoImpl();
// 创建代理
LogInterceptor logInterceptor = new LogInterceptor();
// 设置需要代理的对象
logInterceptor.setTarget(userDao);
// 创建代理之后的对象
/*
第一个参数: 真实对象的类解析器
第二个参数: 实现的接口数组
第三个参数: 调用代理方法的时候,会将方法分配给该参数
*/
IUserDao userDaoProxy = (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
new Class[]{IUserDao.class}, logInterceptor);
userDaoProxy.insert(null);
}
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
2.5 AOP相关术语
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点.
Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置 通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类 动态地添加一些方法或 Field.
Target(目标对象): 代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程,spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入
Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合
2.6 注解方式
2.6.1 引入jar包
还是之前IOC的 再次引入三个就行,因为Spring的AOP是基于AspectJ开发的
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 增加了切面 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
2.6.2 配置文件
1.引入AOP约束,通过配置文件
<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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--开启AOP注解-->
<aop:aspectj-autoproxy />
</beans>
2.通过注解的方式开启切面支持 @EnableAspectJAutoProxy
2.6.3 AOP类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogInterceptor {
@Pointcut("execution(public * com.tledu.zrz.spring.service..*.add(..))")
public void myMethod() {
// 假设这个方法就是被代理的方法
}
@Before("myMethod()")
public void beforeMethod() {
System.out.println(" execute start");
}
@After("myMethod()")
public void afterMethod() {
System.out.println(" execute end");
}
// 环绕,之前和之后都有,相当于 @Before 和 @After 一起使用
@Around("myMethod()")
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
// @Around也可以和@Before 和 @After 一起使用
System.out.println("around start");
// 调用被代理的方法
pjp.proceed();
System.out.println("around end");
}
}
规则:https://blog.csdn.net/q258523454/article/details/104180475
在配置方法的时候,方法可以添加参数JoinPoint joinPoint,通过这个参数可以拿到当前调用的信息,方便我们进行后续的处理。(https://blog.csdn.net/qq_15037231/article/details/80624064)
@After("myMethod()")
public void after(JoinPoint joinPoint) {
System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
System.out.println("目标方法参数:" + joinPoint.getArgs());
System.out.println("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
}
@Pointcut 规则 https://www.cnblogs.com/itsoku123/p/10744244.html
2.6.4 测试类
@Test
public void testAdd() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"beans.xml");
UserService userService = (UserService) applicationContext
.getBean("userService");
userService.add(null);
}
前言
MyBatis相信很多人都会使用,但是当MyBatis整合到了Spring中,我们发现在Spring中使用更加方便了。例如获取Dao的实例,在Spring的我们只需要使用注入的方式就可以了使用Dao了,完全不需要调用SqlSession的getMapper方法去获取Dao的实例,更不需要我们去管理SqlSessionFactory,也不需要去创建SqlSession之类的了,对于插入操作也不需要我们commit。
既然那么方便,Spring到底为我们做了哪些工作呢,它如何将MyBatis整合到Spring中的呢,Spring在整合MyBatis时候做了哪些封装,以及做了哪些拓展,又是怎么实现这些封装以及拓展的,让我们来打开这一部分的源代码,一探究竟。
集成
- 引入依赖
<!--引入相关依赖-->
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 与spring整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.7</version>
</dependency>
- 添加mybatis的配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<!--几十个实体类-->
<!-- <typeAlias type="com.tledu.erp.model.User" alias="User"/>-->
<package name="com.tledu.model"/>
</typeAliases>
<mappers>
<package name="com.tledu.erp.mapper"/>
</mappers>
</configuration>
- 添加数据库配置
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
jdbc.max=50
jdbc.min=10
- 配置spring配置文件
<?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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--配置扫描注解-->
<context:annotation-config/>
<!--告诉spring,要扫描com.tledu包下面的注解-->
<context:component-scan base-package="com.tledu"/>
<!--开启切面支持-->
<aop:aspectj-autoproxy/>
<!-- 1) 读取properties中的内容-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 2) 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.max}"/>
<property name="minIdle" value="${jdbc.min}"/>
</bean>
<!-- 3) 获取 SqlSessionFactory 工厂类-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>
<!-- 4) 搜索有哪些 mapper 实现类,把mapper接口自动配置成 spring 中的 <bean>-->
<bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- name="basePackage":(起始)包名, 从这个包开始扫描-->
<property name="basePackage" value="com.tledu.mapper"/>
</bean>
</beans>
- 添加日志配置
### Log4j配置 ###
#定义log4j的输出级别和输出目的地(目的地可以自定义名称,和后面的对应)
#[ level ] , appenderName1 , appenderName2
log4j.rootLogger=DEBUG,console,file
#-----------------------------------#
#1 定义日志输出目的地为控制台
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
####可以灵活地指定日志输出格式,下面一行是指定具体的格式 ###
#%c: 输出日志信息所属的类目,通常就是所在类的全名
#%m: 输出代码中指定的消息,产生的日志具体信息
#%n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#-----------------------------------#
#2 文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.file = org.apache.log4j.RollingFileAppender
#日志文件输出目录
log4j.appender.file.File=log/info.log
#定义文件最大大小
log4j.appender.file.MaxFileSize=10mb
###输出日志信息###
#最低级别
log4j.appender.file.Threshold=ERROR
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#-----------------------------------#
#3 druid
log4j.logger.druid.sql=INFO
log4j.logger.druid.sql.DataSource=info
log4j.logger.druid.sql.Connection=info
log4j.logger.druid.sql.Statement=info
log4j.logger.druid.sql.ResultSet=info
#4 mybatis 显示SQL语句部分
log4j.logger.org.mybatis=DEBUG
#log4j.logger.cn.tibet.cas.dao=DEBUG
#log4j.logger.org.mybatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.org.mybatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.org.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
-
创建mapper
-
测试
-
引入依赖
-
配置mybatis
-
配置spring,在spring中集成mybatis
3.1 读取jdbc配置文件
3.2 配置druid数据库连接池
3.3 配置sqlSessionFactory
3.4 配置mapper扫描 -
可以通过注入的方式使用mapper
4.1 Service没有起名字
4.2 警告useSSL=false
4.3 一直连接不上()
4.4. 为了知道连接不上的原因,添加日志配置
4.5 原因是时区问题,在url中添加时区的配置
通过注解的方式扫描mapper可以通过@MapperScan(“com.tledu.spring_mybatis.mapper”)
事务
添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
增加配置
<!-- 使使用注解配置的事务行为生效 -->
<tx:annotation-driven transaction-manager="txManager"/><!-- 仍然需要一个PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (这个需要的对象是在其他地方定义的) -->
<property name="dataSource" ref="dataSource"/>
</bean>
使用注解
@Transactional(rollbackFor = Exception.class)
public int insert(User user) {
// 根据数据做一些处理
userDao2.insert(user);
addressMapper.insert(new Address());
throw new RuntimeException();
}
流程:
1.增加事务的配置
2.添加事务的注解
a.rollbackFor:回滚的时机
b.isolation:隔离级别
一、知识点
- jdbcTemplate
1.1 概述
它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多的操作模板类。
操作关系型数据的:
JdbcTemplate
HibernateTemplate
操作 nosql 数据库的:
RedisTemplate
操作消息队列的:
JmsTemplate
我们今天的主角在spring-jdbc.jar 中,我们在导包的时候,除了要导入这个 jar 包 外,还需要导入一个 spring-tx.jar(它是和事务相关的)。
1.2 jdbcTemplate对象创建
我们可以参考它的源码,来一探究竟:
public JdbcTemplate() {
}
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
setDataSource(dataSource);
setLazyInit(lazyInit);
afterPropertiesSet();
}
除了默认构造函数之外,都需要提供一个数据源。既然有set方法,依据我们之前学过的依赖注入,我们可以在配置文件中配置这些对象
1.3 配置数据源
1.3.1 环境搭建
增加jdbc的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
1.3.2 配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置扫描注解-->
<context:annotation-config/>
<!--告诉spring,要扫描com.tledu包下面的注解-->
<context:component-scan base-package="com.tledu"/>
<!--加上aop的约束-->
<aop:aspectj-autoproxy/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--最大连接数-->
<property name="maxActive" value="${jdbc.max}"/>
<!--初始空闲池的个数-->
<property name="minIdle" value="${jdbc.min}"/>
</bean>
</beans>
1.4 增删改查
1.4.1 示例数据
创建表:
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci
INSERT INTO `test`.`account` (`id`, `name`, `money`) VALUES ('1', '张三', '99');
INSERT INTO `test`.`account` (`id`, `name`, `money`) VALUES ('2', '李四', '89');
INSERT INTO `test`.`account` (`id`, `name`, `money`) VALUES ('3', '王五', '15645600');
1.4.2 配置jdbcTemplate
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置扫描注解-->
<context:annotation-config/>
<!--告诉spring,要扫描com.tledu包下面的注解-->
<context:component-scan base-package="com.tledu"/>
<!--加上aop的约束-->
<aop:aspectj-autoproxy/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--最大连接数-->
<property name="maxActive" value="${jdbc.max}"/>
<!--初始空闲池的个数-->
<property name="minIdle" value="${jdbc.min}"/>
</bean>
<!-- 配置一个数据库的操作模板:JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
1.4.3 基本使用1
package com.tledu.zrz.spring.jdbctemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
/**
* JdbcTemplate的最基本用法
*/
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//准备数据源:spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("root");
//1.创建JdbcTemplate对象
JdbcTemplate jt = new JdbcTemplate();
//给jt设置数据源
jt.setDataSource(ds);
//2.执行操作
jt.execute("insert into account(name,money)values('ccc',1000)");
}
}
1.4.4 基本使用2
package com.tledu.zrz.spring.jdbctemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* JdbcTemplate的最基本用法
*/
public class JdbcTemplateDemo2 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
jt.execute("insert into account(name,money)values('ddd',2222)");
}
}
1.4.5 增删改查
package com.tledu.zrz.spring.jdbctemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import com.tledu.zrz.spring.model.Account;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* JdbcTemplate的CRUD操作
*/
public class JdbcTemplateDemo3 {
public static void main(String[] args) {
// 1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate", JdbcTemplate.class);
// 3.执行操作
// 保存
jt.update("insert into account(name,money)values(?,?)", "eee", 3333f);
// 更新
jt.update("update account set name=?,money=? where id=?", "test", 4567,
7);
// 删除
jt.update("delete from account where id=?", 8);
// 查询所有
List<Account> accounts = jt.query(
"select * from account where money > ?",
new AccountRowMapper(), 1000f);
accounts = jt.query("select * from account where money > ?",
new BeanPropertyRowMapper<Account>(Account.class), 1000f);
for (Account account : accounts) {
System.out.println(account);
}
// 查询一个
accounts = jt.query("select * from account where id = ?",
new BeanPropertyRowMapper<Account>(Account.class), 1);
System.out.println(accounts.isEmpty() ? "没有内容" : accounts.get(0));
// 查询返回一行一列(使用聚合函数,但不加group by子句)
Long count = jt.queryForObject(
"select count(*) from account where money > ?", Long.class,
1000f);
System.out.println(count);
}
}
/**
* 定义Account的封装策略
*/
class AccountRowMapper implements RowMapper<Account> {
/**
* 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
*
* @param rs
* @param rowNum
* @return
* @throws SQLException
*/
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
}
1.5 Dao中使用jdbcTemplate
1.5.1 实体类
packagecom.tledu.zrz.spring.model;
importjava.io.Serializable;
/**
* 账户的实体类
*/
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
1.5.2 持久化层接口
packagecom.tledu.zrz.spring.dao;
importcom.tledu.zrz.spring.model.Account;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 根据Id查询账户
* @param accountId
* @return
*/
Account findAccountById(Integer accountId);
/**
* 根据名称查询账户
* @param accountName
* @return
*/
Account findAccountByName(String accountName);
/**
* 更新账户
* @param account
*/
voidupdateAccount(Account account);
}
1.5.3 第一种:dao定义jdbcTemplate
1.5.3.1 实现类
packagecom.tledu.zrz.spring.dao.impl;
importorg.springframework.jdbc.core.BeanPropertyRowMapper;
importorg.springframework.jdbc.core.JdbcTemplate;
importcom.tledu.zrz.spring.dao.IAccountDao;
importcom.tledu.zrz.spring.model.Account;
importjava.util.List;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public voidsetJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",newBeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",newBeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw newRuntimeException("结果集不唯一");
}
return accounts.get(0);
}
@Override
public voidupdateAccount(Account account) {
jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
1.5.3.3 测试
package com.tledu.zrz.spring.jdbctemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tledu.zrz.spring.dao.IAccountDao;
import com.tledu.zrz.spring.model.Account;
/**
* JdbcTemplate的最基本用法
*/
public class JdbcTemplateDemo4 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);
Account account = accountDao.findAccountById(1);
System.out.println(account);
account.setMoney(30000f);
accountDao.updateAccount(account);
}
}