spring mybatis整合

spring的声明式事务管理,可以回滚service的操作(当遇到异常情况时)

    Class Log{
      Propagation.REQUIRED
      insertLog();
    }

    Propagation.REQUIRED
    void saveDept(){
      insertLog();//加入当前事务
      ..异常部分
      saveDept();
    }

    Class LOg{
      Propagation.REQUIRED_NEW
       insertLog();
    }
      Propagation.REQUIRED
    void saveDept(){
      insertLog();//始终开启事务
      ..异常部分,日志不会回滚
      saveDept();
    }

Aop(aspect object programming): 面向切面编程

  • 功能:让关注点代码与业务代码分离!
  • 关注点: 重复代码就叫做关注点;
  • 切面: 关注点形成的类,就叫切面(类).
  • 面向切面编程,就是指对很多功能都有的重复的代码抽取,再在运行的时候往业务方法上动态植入“切面类代码”。
  • 切入点: 执行目标对象方法,动态植入切面代码。可以通过切入点表达式,指定拦截哪些类的哪些方法;给指定的类在运行的时候植入切面类代码。(根据需要进行拦截,是否需要拦截)切入点表达式,可以对指定的“方法”进行拦截; 从而给指定的方法所在的类生层代理对象。

spring七大模块详解

spring 代理理解

动态代理,用工厂类实现--需要实现接口

1.测试类 
ApplicationContext ac = new ClassPathXmlApplicationContext("com/coffee/aop/bean.xml");
/**
 * 动态代理(jdk代理)
 *
 * @throws Exception
 */
@Test
public void testAop() throws Exception {

    // 调用工厂类,获取注解
    IUserDao userDao = (IUserDao) ac.getBean("userDaoProxy");
    // 代理对象:class com.sun.proxy.$Proxy5
    System.out.println(userDao.getClass());
    userDao.save();
}

2.代理工厂类--用反射实现

@Component("userDaoProxy")
public class ProxyFactory {

   private static Object target;
   private static Aop aop;

   public static Object getProxyInstance(Object target_, Aop aop_) {
        target = target_;
        aop = aop_;

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                 target.getClass().getInterfaces(), new InvocationHandler() {

                      @Override
                      public Object invoke(Object proxy, Method method,
                                Object[] objects) throws Throwable {

                           // 在核心业务代码执行前,,引入重复执行的代码
                           aop.begin();
                           Object returnValue = method.invoke(target, objects);
                           // 核心代码结束后执行收尾工作
                           aop.commit();
                           return returnValue;
                      }
                 });

   }

动态代理--不需要使用工厂类,用注解

1.dao层,加注解@Repository("userDao")

@Repository("userDao")
public class UserDao implements IUserDao {

   public void save() {
        // 获取session/处理异常--每次都要重复执行此类代码:被称为【关注点代码:就是重复执行的代码】
        System.out.println("UserDao 核心业务代码:保存数据。。");// 这才是真正的核心业务代码:【关键点代码】
        // 关闭session/处理异常--每次都要重复执行此类代码:【关注点代码:就是重复执行的代码】
   }

2.bean.xml

首先开启注解扫描

然后开启aop自动实现代理

    
    
    
    

cglib代理:实现的cglib代理的类不能是final

cglib代理:需要引入spring-core.jar文件

1.测试类

/**
  * 注解代理:目标类没有实现接口,aop自动执行 cglib代理
  *
  * @throws Exception
  */
 @Test
 public void testCglibAop() throws Exception {

      // 调用工厂类
      OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
      // 代理对象:class com.sun.proxy.$Proxy5
      System.out.println(orderDao.getClass());
      orderDao.save();
 }

2.dao层加注解

// 将目标对象加入ioc
@Repository("orderDao")
public class OrderDao {// 没有实现接口,使用cglib代理
     public void save() {
          System.out.println("OrderDao 核心业务代码:保存数据。。");// 这才是真正的核心业务代码:关键点代码
     }

3.bean.xml配置注解,开启aop

首先开启注解扫描

然后开启aop自动实现代理






cglib底层实现

public class ProxyFactory_cglib implements MethodInterceptor {

     private Object target;// 维护代理对象

     public ProxyFactory_cglib(Object target) {
          this.target = target;
     }

     // 给目标对象创建代理对象
     public Object getProxyInstance() {
          // 1. 工具类,在引入的jar文件中spring-core.jar
          Enhancer enhancer = new Enhancer();
          // 2. 设置父类
          enhancer.setSuperclass(target.getClass());
          // 3. 设置回掉函数
          enhancer.setCallback(this);
          // 4. 创建子类代理对象,,,,所以使用cglib代理的dao不能是final的
          return enhancer.create();
     }

关注点代码&&关键点代码

dao层

public void save() {
    // 获取session/处理异常--每次都要重复执行此类代码:被称为【关注点代码:就是重复执行的代码】
    System.out.println("UserDao 核心业务代码:保存数据。。");// 这才是真正的核心业务代码:【关键点代码】
    // 关闭session/处理异常--每次都要重复执行此类代码:【关注点代码:就是重复执行的代码】
}

切入点表达式

bean.xml:



  
  


  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  
  
      
      
      
      
      
      
      
      
      
      
  


aop切面类:

public class Aop {

 public void begin() {
      System.out.println("开始事务/异常");
 }

 public void after() {
      System.out.println("提交事务/关闭");
 }

 public void afterReturning() {

      System.out.println("afterReturning()");
 }

 // 目标方法异常处理
 public void afterThrowing() {

      System.out.println("afterThrowing()");
 }

 public void around(ProceedingJoinPoint pjp) throws Throwable {

      System.out.println("环绕前执行。。相当于@Before()");
      pjp.proceed();
      System.out.println("还绕后执行。。相当于@After()");
 }
}

// 事务传播的属性
@Service
public class T_DeptService {

 @Resource
 // 加入容器
 T_DeptDao t_DeptDao = new T_DeptDao();
 @Resource
 LogsDao logsDao = new LogsDao();

 // 事务传播的属性
 @Transactional(
 // readOnly = false,
 // timeout = -1,
 // noRollbackFor = ArithmeticException.class 遇到异常不回滚
 // propagation=Propagation.REQUIRED Propagation.REQUIRED
 // 指定当前的方法必须在事务的环境下执行;
 // 如果当前运行的方法,已经存在事务, 就会加入当前的事务,受当前事务约束;
 // Propagation.REQUIRED_NEW
 // 指定当前的方法必须在事务的环境下执行;
 // 如果当前运行的方法,已经存在事务: 事务会挂起(就像遇到异常不回滚此方法); 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。

 )
 // 必须加上这个注解才能实现注解的spring事务控制,这个注解可以加载类上,父类上,范围范围根据加在什么上面而不同
 public void save(T_Dept t_Dept) {

      logsDao.insertlog();
      int i = 1 / 0;// 模拟中间的异常,配置spring事务控制后遇到异常就会回滚,即上面的数据库操作无效
      t_DeptDao.save(t_Dept);
 }


    
      
      
      
      
      
      
      
      
    
    
    
      
    

pring声明式事务管理




  



  
  
      
      
      
  



  
  
  

mybatis中的sqlsession工具类

package utils;

import java.io.IOException;
import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * 加载mybatis配置文件
 * @author wangan
 *
 */
public class MybatisUtil {

    // 本地线程,用于绑定session,,SqlSession是mybatis里面的创建session的类,hibernate是session
    private static ThreadLocal threadLocal = new ThreadLocal();

    private static SqlSessionFactory sqlSessionFactory;

    // 私有化无参构造,防止人为不断new他
    private MybatisUtil() {
    }

    // 使用static静态块的好处就是加载快,只能加载一次
    static {
        try {
            // 加载src/mybatis.xml
            Reader reader = Resources.getResourceAsReader("mybatis.xml");
            // 加载reader,创建sqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 返回session
     */
    public static SqlSession getSqlSession() {

        SqlSession sqlSession = threadLocal.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            // 本地线程绑定sqlsession
            threadLocal.set(sqlSession);

        }
        return sqlSession;
    }

    /**
     * 关闭session
     */

    public static void closeSqlSession() {
        SqlSession sqlSession = threadLocal.get();
        if (sqlSession != null) {
            // 关闭session
            sqlSession.close();
            // 移除session,供GC回收,不然多次访问数据库后会变慢
            threadLocal.remove();

        }
    }

}

映射配置





          
     
          
          
          
          
          
     

 
       
 
      
      insert into students values(1,'张三',7000)
 

 
 
      
      insert into students values(#{id},#{name},#{sal})
 

 
 
      update students set name=#{name},sal=#{sal} where id=#{id}
 

 
 

 
 

 
 
      delete from students where id=#{id}
 

 
 
 

 
 

 
 
      update students
          
               
                    name=#{name},
               
               
                    sal=#{sal}
               
          
               where id=#{id}
 

 
 
      

      delete from students where id in
      
           #{ids}
      

 

 
 
      delete from students where id in
          
               #{list}
          
 

 
 

 
 
      insert into students (id,name,sal)
          values(#{id},#{name},#{sal})
 

dao调用

package com.coffee.mybatis01.dao;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;

import utils.MybatisUtil;

import com.coffee.mybatis01.entity.Student;

/**
 * 数据访问层
 * @author wangan
 *
 */
public class StudentDao {

    /**
     * 添加学生--无参
     * @param student
     */
    public void add1() throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        sqlSession.insert("studentNamespace.add1");

        try {
            sqlSession.commit();

        } catch (Exception e) {
            // 回滚操作
            sqlSession.rollback();
            throw new RuntimeException(e);
        } finally {
            MybatisUtil.closeSqlSession();
        }

    }

    /**
     * 添加学生--有参
     * @param student
     */
    public void add2(Student student) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        // 插入对象,指定映射空间名称,和标签的id

        try {
            sqlSession.insert("studentNamespace.add2", student);

        } catch (Exception e) {
            sqlSession.rollback();
            throw new RuntimeException(e);
        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }
    }

    /**
     * 修改学生
     * @param student
     */

    public void update(Student student) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.update("studentNamespace.update", student);
        } catch (Exception e) {
            sqlSession.rollback();

        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }
    }

    /**
     * 查询所有学生
     * @param student
     */

    public List findAll() throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        List studentList = new ArrayList();
        try {
            studentList = sqlSession.selectList("studentNamespace.findAll");
        } catch (Exception e) {
            sqlSession.rollback();

        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }

        return studentList;
    }

    /**
     * 根据id查询学生
     * @param student
     */

    public Student findById(int id) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        Student student = new Student();
        try {
            student = sqlSession.selectOne("studentNamespace.findById", id);
            sqlSession.commit();
        } catch (Exception e) {
            sqlSession.rollback();

        } finally {
            MybatisUtil.closeSqlSession();
        }
        return student;
    }

    /**
     * 删除学生
     * @param student
     */

    public void delete(int id) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.delete("studentNamespace.delete", id);
            sqlSession.commit();
        } catch (Exception e) {
            sqlSession.rollback();

        } finally {
            MybatisUtil.closeSqlSession();
        }
    }

    /**
     * 分页查询--无条件
     */

    public List findPage(int start, int end) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        List students = new ArrayList();
        try {
            Map map = new LinkedHashMap();
            map.put("start", start);
            map.put("end", end);

            students = sqlSession.selectList("studentNamespace.findPage", map);
            sqlSession.commit();
        } catch (Exception e) {
            sqlSession.rollback();

        } finally {
            MybatisUtil.closeSqlSession();
        }
        return students;
    }

    /**
     * 动态sql查询--参数使用包装类型进行条件判断时如果是null代表不限,不确定,任意
     */
    public List dynaSelect(Integer id, String name, Double sal)
            throws Exception {

        SqlSession sqlSession = MybatisUtil.getSqlSession();
        List list = new ArrayList();
        try {
            Map map = new LinkedHashMap();

            map.put("pid", id);
            map.put("pname", name);
            map.put("psal", sal);

            list = sqlSession.selectList("studentNamespace.dynaSelect", map);
        } catch (Exception e) {
            sqlSession.rollback();
            throw new RuntimeException(e);
        } finally {
            MybatisUtil.closeSqlSession();
        }
        return list;
    }

    /**
     * 动态sql更新
     */
    public void dynaUpdate(Student student) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.update("studentNamespace.dynaUpdate", student);
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }

    }

    /**
     * 动态sql迭代数组--根据id删除多个
     */
    public void dynaDelete(int... ids) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.delete("studentNamespace.dynaDelete", ids);
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }

    }

    /**
     * 动态sql迭代list集合--根据id删除多个
     */
    public void dynaDeleteList(List list) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.delete("studentNamespace.dynaDeleteList", list);
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }

    }

    /**
     * 动态sql插入对象
     */
    public void dynaInsert(Student student) throws Exception {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        try {
            sqlSession.insert("studentNamespace.dynaInsert", student);
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.commit();
            MybatisUtil.closeSqlSession();
        }

    }

}

整合之注册功能

spring.xml配置文件




  
  
      
      
      
      
  

  
  
      
      
      
      
  

  
  
      
      
  

  
  
      
          
          
      
  

  
  
      
      
  


  
  
      
  
  
  
      
  

  
  


  
  



  
 
      
      
  



dao

package com.coffee.dao;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.coffee.entity.Student;

/**
 * 数据访问--StudentDao
 * @author wangan
 *
 */
public class StudentDao {

    // 注入sqlsession工厂
    private SqlSessionFactory sqlSessionFactory;

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    /**
     * 添加学生
     * @param student
     * @throws Exception
     */
    public void add(Student student) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.insert("studentNamespace.add", student);
        sqlSession.close();

    }
}

service

package com.coffee.service;

import com.coffee.dao.StudentDao;
import com.coffee.entity.Student;

/**
 * 数据访问
 * @author wangan
 *
 */
public class StudentService {

    private StudentDao studentDao;

    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    public void register(Student student) throws Exception {
        try {
            studentDao.add(student);
        } catch (Exception e) {

            e.printStackTrace();
        }

    }
}

Action

package com.coffee.action;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.coffee.entity.Student;
import com.coffee.service.StudentService;

/**
 * action
 * @author wangan
 *
 */
@Controller
@RequestMapping(value = "/student")
public class StudentAction {

    private StudentService studentService;

    @Resource(name = "studentService")
    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }

    /**
     * 注册学生
     * @param student
     * @return
     */
    @RequestMapping(value = "/register")
    public String registerStudent(Student student) {
        try {
            studentService.register(student);
        } catch (Exception e) {

            e.printStackTrace();
        }
        return "success";
    }

}

test

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.coffee.dao.StudentDao;
import com.coffee.entity.Student;

/**
 * 测试整合
 * @author wangan
 *
 */
public class TestSpring_mybatis {

    public static void main(String[] args) {

        Student student = new Student(20, "王林", 8000d);

        ApplicationContext ac = new ClassPathXmlApplicationContext(
                new String[] { "spring.xml" });
        StudentDao studentDao = (StudentDao) ac.getBean("studentDao");
        try {
            studentDao.add(student);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

web.xml



  sshProject2



   struts2
     org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter


   struts2
   /*




   contextConfigLocation
   classpath:bean.xml



     org.springframework.web.context.ContextLoaderListener



  index.jsp


struts.xml



 
      
      
          
          
          
          
      
 
 
 

UserInterceptor.java

package com.coffee.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * 管理员拦截器
 * 较验用户是否登陆,只有登陆后才可以进行操作。
 * 没有登陆,只能查看列表,不能操作!
 * @author wangan
 *
 */
@SuppressWarnings("all")
public class UserInterceptor extends AbstractInterceptor {

    @Override
    // 所有的拦截器都会调用此方法
    public String intercept(ActionInvocation invocation) throws Exception {
        // 1.得到当前执行的方法--代理获取方法
        String methodName = invocation.getProxy().getMethod();
        // 2.得到actionContext对象
        ActionContext context = invocation.getInvocationContext();
        // 3.获取session,从session获取登录用户对象
        Object object = context.getSession().get("adminInfo");
        // 4.判断方法是否放行,登录方法放行
        if (!"login".equals(methodName) && !"list".equals(methodName)) {
            if (object == null) {
                // 没有登录
                return "login";
            } else {
                // 执行action ,放行
                return invocation.invoke();
            }
        } else {
            // 允许访问登录/列表展示
            return invocation.invoke();
        }
    }

}

数据回显

/**
  * 3. 修改员工-进入修改页面(list.jsp里面的修改 链接跳转到这里)
  * struts2的保存修改数据的方式就是模型驱动,先把旧的数据移除,新的压进栈
  */
public String viewUpdate() {// 更新一条记录的关键步骤
      // 1.获取主键
      int id = employee.getEmployeeId();
      // 2.根据员工的主键查询,此时已经有部门信息(lazy=false)
      Employee employee = employeeService.findById(id);
      // 3. 查询所有的部门信息
      List listDept = deptService.getAll();

      // 4.数据回显
      // 获取valueStack对象
      ValueStack valueStack = ActionContext.getContext().getValueStack();
      // 移除栈顶元素(旧的)
      valueStack.pop();
      // 入栈,即将更新的值
      valueStack.push(employee);
      request.put("listDept", listDept);
      return "edit";

}

下拉列表


    
    

做注册的时候员工的信息联系到另外一张表部门表,下拉菜单选择部门的时候这个deptid顺带传过去提交到注册action

// 封装部门id,下拉列表里面的name=“deptid”的值
 private int deptid;

 public void setDeptid(int deptid) {
      this.deptid = deptid;
 }

 public int getDeptid() {
      return deptid;
 }


//注册
public String save() {
          // 先根据部门主键查询
          Dept dept = deptService.findById(deptid);
          // 部门设置到员工对象中
          employee.setDept(dept);
          // 保存员工
          employeeService.save(employee);

          return "listAction";// 重定向到Action
     }

mybatis工作流程:

1️⃣ 通过Reader对象读取src目录下面的mybatis.xml配置文件(可自定义路径)
2️⃣ 通过SqlSessionBuilder对象创建SqlSessionFactory对象
3️⃣ 从当前线程中获取SqlSession对象
4️⃣ 事物开始,在mybatis中默认
5️⃣ 通过SqlSession对象读取StudentMapper.xml映射文件中的操作编号,从而读取sql语句
6️⃣ 事物必须提交
7️⃣ 关闭SqlSession对象.并且分开当前线程与SqlSession对象,让GC尽早回收

批量插入数据--list集合


INSERT INTO BUY_ORDER_DETAIL (BOD_ID, GOODS_ID, GOODS_NAME,
GOODS_UNIT, GOODS_TYPE, GOODS_COLOR,
BOD_AMOUNT, BOD_BUY_PRICE, BOD_TOTAL_PRICE,
BO_ID, BOD_IMEI_LIST)

SELECT
#{item.bodId,jdbcType=VARCHAR}, #{item.goodsId,jdbcType=VARCHAR},
#{item.goodsName,jdbcType=VARCHAR},#{item.goodsUnit,jdbcType=VARCHAR},
#{item.goodsType,jdbcType=VARCHAR}, #{item.goodsColor,jdbcType=VARCHAR},
#{item.bodAmount,jdbcType=DECIMAL}, #{item.bodBuyPrice,jdbcType=DECIMAL},
#{item.bodTotalPrice,jdbcType=DECIMAL}, #{item.boId,jdbcType=VARCHAR},
#{item.bodImeiList,jdbcType=CLOB}
FROM DUAL






错误例2:将整个sql语句用

标记来避免冲突,在一般情况下都是可行的,是由于该sql配置中有动态语句(where部分),将导致系统无法识别动态判断部分,导致整个sql语句非法。

      正确做法:缩小范围,只对有字符冲突部分进行合法性调整。

ibatis中应该经常见到       大于号 
&                &       和 
'               '       单引号 
"               "       双引号 

你可能感兴趣的:(spring mybatis整合)