目录
JdbcTemplate.batchUpdate(批量增删改)
JdbcTemplata.QueryForOBject获取信息
动态代理
动态代理是java的一种设计模式。它的特征就是委托类和代理类具有相同的接口,代理类是在委托类的代码基础上添加了其他功能,比如消息预处理、消息过滤和事后处理消息等。但是实际上业务逻辑还是有委托类去完成的,简单来说,调用委托类的时候是通过代理对象来实现的。
代理类是在程序运行的时候 创建的所以被称为动态代理。动态代理相对于静态代理更加灵活,能够根据java代码指示动态生成
创建一个接口 作用是加减乘除
public interface MathI {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
创建一个类来实现这个接口
public class MathImpl implements MathI {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
System.out.println("method:div,arguments:"+i+","+j);
int result = i / j;
System.out.println("method:div,result:"+result);
return result;
}
}
创建一个工具类
public class Mylogger {
public static void before(String methodName,String args){
System.out.println("method:"+methodName+",arguments:"+args);
}
public static void after(String methodName,Object result){
System.out.println("method:"+methodName+",result:"+result);
}
}
创建一个动态代理的类
public class ProxyUtil {
public ProxyUtil(MathImpl mathImpl) {
this.mathImpl = mathImpl;
}
private MathImpl mathImpl;
public Object getProxy() {
//获取当前类的加载器,用来加载代理对象实现所属类
ClassLoader loader = this.getClass().getClassLoader();
//获取目标对象实现所有接口的class,代理类会和目标类实现相同的功能
Class[] interfaces = mathImpl.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Mylogger.before(method.getName(), Arrays.toString(args));
Object result=method.invoke(mathImpl, args);//动态代理对象实现功能
Mylogger.after(method.getName(),result);
return result;
}
});
}
}
测试
public class Test {
public static void main(String[] args) {
ProxyUtil proxy=new ProxyUtil(new MathImpl());
MathI math=(MathI) proxy.getProxy();
int i=math.add(1,1);
System.out.println(i);
}
}
aop专业术语
- Advice (增强/通知) 表示需要扩展的功能(前置通知,后置通知,返回通知,异常通知,环绕通知)。就是各个方法
- JoinPoint (连接点) 表示允许使用增强的地方。基本每个方法的前、后或异常等都是连接点。也就是切面作用作用于目标对象方法中的位置
- Pointcut (切入点) 表示实际增强的方法。切入点表达式(value = "execution(* aop.*.*(..))")
- Aspect (切面) 表示扩展功能的过程。也就是把非核心业务放到一个类,这个类就叫切面
- Introduction( 引入) 表示向现有的类中添加新方法、新属性。
- Target (目标对象) 表示被增强的对象。
- Proxy (代理) 表示实现AOP的机制。
- Weaving (织入) 表示把增强应用到目标对象的过程。
- 横切关注点:从每个方法中抽取出来的非核心业务,放到切面就叫通知
前置通知
不管是什么通知 都要在放通知的类里面加
@Component//扫描组件 @Aspect//标注当前类为切面 @Order(1)//定义切面作用的优先级,值越小优先级越高,默认值为int的最大值
@Before:将方法设置为前置通知 必须设置value 其值表示切入点表达式
value="execution(属性类型 包名.类名.方法(形参列表类型))"
Object[] args=joinPoint.getArgs();//获取方法参数
String MethodName=joinPoint.getSignature().getName();//获取方法名
public class MyloggerAspect {
//@Before(value = "execution(public int aop.MathImp.add(interestin,int))")//
@Before(value = "execution(* aop.*.*(..))")//第一个个*代表任意的返回值类型,第二个*代表任意的类,第三个*代表任意的方法,..代表任意类型的参数
public void beforeMethod(JoinPoint joinPoint){//JoinPoint 连接点
Object[] args=joinPoint.getArgs();//获取方法参数
String MethodName=joinPoint.getSignature().getName();//获取方法名
System.out.println("MethodName:"+MethodName+",argsments:"+ Arrays.toString(args));
}
}
后置通知
@after:将方法设置成后置通知,在方法执行之后运行
@After(value = "execution(* aop.*.*(..))")
public void afterMethod(){
System.out.println("后置通知");
}
不管是前置通知还是后置通知 都要在放通知的类里面加
@Component//扫描组件 @Aspect//标注当前类为切面 @Order(1)//定义切面作用的优先级,值越小优先级越高,默认值为int的最大值
返回通知
@AfterReturning:将方法设置为返回通知,是在方法执行之后运行
可以通过returning设置接受方法返回值的变量 要想在方法中使用,必须要在方法的形参列表中设置和变量名相同的参数名的参数
@AfterReturning(value = "execution(public int aop.MathImpl.add(int,int))",returning = "result")
public void afterreturning(JoinPoint joinPoint,Object result){
String methodName=joinPoint.getSignature().getName();
System.out.println("方法名字:"+methodName+"结果"+result);
}
异常通知
@AfterThrowing(value = "execution(* aop.*.*(..))",throwing = "ex")
public void afterthrowing(Exception ex){
System.out.println("有异常了aaaaa,,异常信息:"+ex);
}
@AfterThrowing:将方法设为异常通知,作用于方法抛出异常时
可通过throwing设置接受方法的异常信息
在参数列表中通过具体的异常类型(ArithmeticException ex)来对指定的异常信息进行操作
环绕通知:
环绕通知是所有通知类型中功能最为强大的, 能够全面地控制连接点. 甚至可以控制是否执行连接点.
@Around(value = "execution(* aop.*.*(..))")
public Object arounemethod(ProceedingJoinPoint joinPoint){
Object resutl=null;
try {
System.out.println("前置通知");
joinPoint.proceed();//执行方法
System.out.println("放回通知");
return resutl;
} catch (Throwable e) {
System.out.println("异常通知");
e.printStackTrace();
}finally {
System.out.println("后置通知");
}
return -1;
}
公共切入点
@Pointcut:定义一个公共切入点
@Pointcut(value = "execution(* aop.*.*(..))")
public void test(){}
//后面要选择切入点直接用这个方法就行
@After(value = "test()")
public void afterMethod(){
System.out.println("后置通知");
}
xml配置aop
<aop:config>
<!-- 声明切面,切面类id可以自己取,或者用系统默认的就是扫描类的首字母小写的类名 -->
<aop:aspect ref="切面类id">
<!-- 抽取切点表达式 -->
<aop:pointcut id="切点id" expression="切点表达式"/>
<!-- 设置增强 -->
<aop:增强方式 method="增强方法名" pointcut-ref="切点id"></aop:增强方式>
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspect ref="myLogger">
<aop:pointcut expression="execution(* com.atguigu.spring.aopxml.*.*(..))" id="cut"/>
<!-- <aop:before method="before" pointcut="execution(* com.atguigu.spring.aopxml.*.*(..))"/> -->
<aop:before method="before" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
JdbcTemplate
搭建:
<!-- 创建数据连接池,也就是数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.dirver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.passwors}"></property>
</bean>
<!--通过数据源配置jdbcTemplate ,其中ref就是数据源的id -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 引入属性文件,也就是为数据连接池里的赋值 -->
<!--写法一: -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="db.properties"></property>
</bean>
<!--写法二 -->
<context:property-placeholder location="db.properties"/>
properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=123456
JdbcTemplate.update(增删改) 数据更新
@Test
public void test() {
jdbcTemplate.update("insert into emp value(null,'张山',23,'男')");
String sql="insert into emo value(null,?,?,?)";
jdbcTemplate.update(sql, "李四",24,'女')
}
JdbcTemplate.batchUpdate(批量增删改)
@Test
public void testBatchUpdate() {
String sql="insert into imp value(null,?,?,?')";
List <Object[]>list=new ArrayList();
list.add(new Object[]{"a1",24,'男'});
list.add(new Object[] {"a2",25,'女'});
jdbcTemplate.batchUpdate(sql,list)
//批量删除
String eids = "3,4,5";
String sql = "delete from emp where eid in ("+eids+")";
jdbcTemplate.update(sql);
}
JdbcTemplata.QueryForOBject获取信息
@Test
public void testQueryForObject() {
String sql="select eid,ename,age,sex,from emp where eid=?";
RowMapper<Emp> rowMapper=new BeanPropertyRowMapper<Emp>(Emp.class);
Emp queryForObject = jdbcTemplate.queryForObject(sql, new Object[]
{1},rowMapper);
System.out.println(queryForObject);//就可以打印eid=1的数据
}
query查询
@Test
public void testQuery() {
String sql="select eid,ename,age,sex from emp";
RowMapper<Emp> rowmapper=new BeanPropertyRowMapper<Emp>(Emp.class);
List<Emp> list = jdbcTemplate.query(sql, rowmapper);
for (Emp emp : list) {
System.out.println(emp);
}
}
事务问题演示
事务时逻辑上紧密关联二合并成一个整体,这些操作要么都执行,要么都不执行
模拟买书:
创建daor层
public interface BookDao {
Integer selectPrice(String bid);// 查询价格
void updateSt(String bid);//更新买完后书的库存
void updateBalance(String uid, Integer price);//更新余额
}
@Repository
public class BookDaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;//JdbcTemplate连接数据库
@Override
public Integer selectPrice(String bid) {
Integer price = jdbcTemplate.queryForObject("select price from book where bid = ?", new Object[] {bid}, Integer.class);
return price;
}
@Override
public void updateSt(String bid) {
//获取该书籍的库存
Integer st = jdbcTemplate.queryForObject("select st from stock where sid = ?", new Object[] {bid}, Integer.class);
if(st <= 0) {
throw new RuntimeException();
}else {
jdbcTemplate.update("update stock set st = st -1 where sid = ?", bid);
}
}
@Override
public void updateBalance(String uid, Integer price) {
Integer balance=jdbcTemplate.queryForObject("select balance from money where uid=?",new Object[] {uid},Integer.class);
if(price>balance) {
throw new MyException("余额不足");
}else {
jdbcTemplate.update("update money set balance=balance-? where uid=?",price,uid);
}
}
}
service层
public interface BookService {
void buyBook(String bid, String uid);
}
@Service public class BookServiceImpl implements BookService { //seveice调用dao @Autowired private BookDao dao; public void buyBook(String bid, String uid) { Integer price = dao.selectPrice(bid); dao.updateSt(bid); dao.updateBalance(uid, price); } }
controller层
@Controller
public class BookController {
//controller 调用sever
@Autowired
private BookService service;
public void buyBook() {
service.buyBook("1", "1001");
}
}
测试
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("conf/book.xml");
BookController controller = ac.getBean("bookController", BookController.class);
controller.buyBook();
}
}