美文网首页
spring mybatis整合

spring mybatis整合

作者: annkee | 来源:发表于2018-07-10 11:21 被阅读0次

    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

    首先开启注解扫描

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

    然后开启aop自动实现代理

        <!-- 注解实现 aop编程 -->
        <!-- 1.在命名空间引入 aop相关头 -->
        <!-- 2.开启 aop注解 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    

    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

    首先开启注解扫描

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

    然后开启aop自动实现代理

    <!-- 注解实现 aop编程 -->
    <!-- 1.在命名空间引入 aop相关头 -->
    <!-- 2.开启 aop注解 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    

    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 -->
    <aop:config>
      <!-- 定义一个切入点表达式 ,指定拦截哪些类的哪些方法-->
      <aop:pointcut expression="execution(* com.coffee.pointcut.*.*(..))" id="pt"/>
    
    <!-- 从这开始#######【下面是测试别的方法】######### -->
      <!-- 拦截所有的public方法-->
      <aop:pointcut expression="execution(public * *(..))" id="pt"/>
      <!-- 拦截所有的save方法-->
      <aop:pointcut expression="execution(* save*(..))" id="pt"/>
      <!-- 拦截指定类的指定的指定方法,具体到方法-->
      <aop:pointcut expression="execution(* com.coffee.pointcut.OrderDao.save(..))" id="pt"/>
      <!-- 拦截指定类的指定的所有方法,具体到类-->
      <aop:pointcut expression="execution(* com.coffee.pointcut.OrderDao.*(..))" id="pt"/>
      <!-- 拦截指定包,及其子包下的的所有类的所有方法 -->
      <aop:pointcut expression="execution(* com..*.*(..))" id="pt"/>
      <!-- 【多个表达式】 -->
      <!-- 拦截或的关系的方法,不能用and 或者&& -->
      <aop:pointcut expression="execution(* com.coffee.pointcut.OrderDao.save()) || execution (* com.coffee.pointcut.UserDao.save())" id="pt"/>
      <aop:pointcut expression="execution(* com.coffee.pointcut.OrderDao.save(..))) || execution(* com.coffee.pointcut.UserDao.save())" id="pt"/>
      <!-- 取非值 -->
      <aop:pointcut expression="!execution(* com.coffee.pointcut.OrderDao.save())" id="pt"/>
      <!-- not 前要加空格,和上面等价 -->
      <aop:pointcut expression=" not execution(* com.coffee.pointcut.OrderDao.save())" id="pt"/>
    <!-- 从这结束################ -->
      <!-- 切面配置 -->
      <aop:aspect ref="aop">
          <!-- 环绕通知 -->
          <aop:around method="around" pointcut-ref="pt"/>
          <!-- 前置通知 -->
          <aop:before method="begin" pointcut-ref="pt"/>
          <!-- 后置通知(最终通知) -->
          <aop:after method="after" pointcut-ref="pt"/>
          <!-- 返回后通知 -->
          <aop:after-returning method="afterReturning" pointcut-ref="pt"/>
          <!-- 异常的通知 -->
          <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
      </aop:aspect>
    
    </aop:config>
    

    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);
     }
    
    <!-- 1.【c3p0连接池 数据源配置(oracle)】 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"></property>
          <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl"></property>
          <property name="user" value="wangan"></property>
          <property name="password" value="666"></property>
          <property name="initialPoolSize" value="3"></property>
          <property name="maxPoolSize" value="10"></property>
          <property name="maxStatements" value="100"></property>
          <property name="acquireIncrement" value="2"></property>
        </bean>
        <!-- 2.【数据库模板】 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
          <property name="dataSource" ref="dataSource"></property>
        </bean>
    

    pring声明式事务管理

    <!-- ####5. spring声明式事务管理器### -->
    <!-- 1. 配置事务管理器类 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 2. 配置事务增强 ,如何管理事务-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
      <tx:attributes>
      <!-- 以get开头/find开头的所有方法只读,剩下的读写 -->
          <tx:method name="get*" read-only="true"/>
          <tx:method name="find*" read-only="true"/>
          <tx:method name="*" read-only="false"/>
      </tx:attributes>
    </tx:advice>
    <!-- 3. 配置aop,拦截哪些方法(切入点表达式)+应用上面的事务增强  -->
    <aop:config>
      <aop:pointcut id="pt" expression="execution(* com.coffee.spring_transaction.T_DeptService.*(..))" /><!-- (..)带上两个点;第一个*式返回值类型 -->
      <!-- 引入切入点表达式 -->
      <aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
    </aop:config>
    

    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<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
    
        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();
    
            }
        }
    
    }
    

    映射配置

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namespace随便起名字 -->
    <mapper namespace="studentNamespace">
              <!--  type="com.coffee.mybatis01.entity.Student"名字太长,用别名在mybatis配置文件配置
                  id属性用来标记resultmap,如果实体类中的属性和表的字段不一致,用id
                  如果都一致,可选
               -->
         <resultMap type="student" id="student">
              <!-- 主键映射 -->
              <id property="id" column="id" />
              <!-- 其他属性映射 -->
              <result property="name" column="name"/>
              <result property="sal" column="sal"/>
         </resultMap>
    
     <!--
          StudentDao里面的add方法,就是插入方法名称(理论上随便起,方便理解就用一样的名字)
          parameterType方法的参数的类型,写全路径
           -->
           <!-- 无参插入( parameterType="com.coffee.mybatis01.entity.Student"省略) -->
     <insert id="add1" >
          <!-- 插入的sql语句 -->
          insert into students values(1,'张三',7000)
     </insert>
    
     <!-- 带参插入 -->
     <insert id="add2"  parameterType="student">
          <!-- 插入的sql语句 #{id}==student.getId(),是占位符的意思,hibernate是:= -->
          insert into students values(#{id},#{name},#{sal})
     </insert>
    
     <!-- 修改值 -->
     <update id="update" parameterType="student">
          update students set name=#{name},sal=#{sal} where id=#{id}
     </update>
    
     <!-- 查询所有
          resultType返回的是集合,但是我就是要遍历出来student,所以只写student类型
      -->
     <select id="findAll" resultType="student">
          select * from students
     </select>
    
     <!-- 根据id查询
          resultMap映射resultMap里的id,代表返回值类型,根据id的类型进行返回值判断,resultType比较精确,resultMap是通用的
     -->
     <select id="findById" parameterType="int" resultMap="student">
          select * from students where id=#{id}
     </select>
    
     <!-- 删除数据 -->
     <delete id="delete" parameterType="int">
          delete from students where id=#{id}
     </delete>
    
     <!-- ###分页操作 -->
     <!-- 无条件分页 -->
     <select id="findPage" resultMap="student">
      select * from students where id between #{start} and #{end}
     </select>
    
     <!-- 动态sql查询 -->
     <select id="dynaSelect" parameterType="map" resultMap="student">
          select * from students
              <where>
                   <!-- kid是map的Key键,test自动判断key值 -->
                   <if test="pid!=null">
                        and id=#{pid}
                   </if>
                   <if test="pname!=null">
                        and name=#{pname}
                   </if>
                   <if test="psal!=null">
                        and sal=#{psal}
                   </if>
    
              </where>
    
     </select>
    
     <!-- 动态sql update更新
          name=#{name},不要忘了逗号','
          -->
     <update id="dynaUpdate" parameterType="student">
          update students
              <set>
                   <if test="name!=null">
                        name=#{name},
                   </if>
                   <if test="sal!=null">
                        sal=#{sal}
                   </if>
              </set>
                   where id=#{id}
     </update>
    
     <!-- 动态sql删除多个#迭代数组 -->
     <delete id="dynaDelete">
          <!-- 删除多个需要遍历数组(这里是数组的遍历array)
                完整的sql是: delete from students where id in (1,3,5)
               collection遍历的类型:array/list
               open开头  close结尾
               item遍历的名称,可以任意写,不需要和dao的一致
               separator分隔符,分割数组的内容
                #{ids}和item的一致
          -->
    
          delete from students where id in
          <foreach collection="array" open="(" close=")" separator=","  item="ids">
               #{ids}
          </foreach>
    
     </delete>
    
     <!-- 动态sql删除多个,迭代list -->
     <delete id="dynaDeleteList">
          delete from students where id in
              <foreach collection="list" open="(" close=")" item="list" separator=",">
                   #{list}
              </foreach>
     </delete>
    
     <!-- ####  动态插入对象 #######-->
     <!--
          insert into students (id,name,value) values (1,"张三",5000.0)
      -->
    <!--      <sql id="key">
    
              <if test="id!=null">id,</if>
              <if test="name!=null">name,</if>
              <if test="sal!=null">sal</if>
    
     </sql>
     <sql id="value">
          trim标签可以去掉,同时把#{sal},的逗号去掉
          <trim suffixOverrides=",">
              <if test="id!=null">#{id},</if>
              <if test="name!=null">#{name},</if>
              <if test="sal!=null">#{sal},</if>
          </trim>
     </sql>
    
     <insert id="dynaInsert">
          insert into students (<include refid="key"></include>)
              values(<include refid="value"></include>)
     </insert> -->
     <!-- 效果同上,都可以插入 -->
     <insert id="dynaInsert">
          insert into students (id,name,sal)
              values(#{id},#{name},#{sal})
     </insert>
    </mapper>
    

    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();
            // 插入对象,指定映射空间名称,和<insert>标签的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<Student> findAll() throws Exception {
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            List<Student> studentList = new ArrayList<Student>();
            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<Student> findPage(int start, int end) throws Exception {
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            List<Student> students = new ArrayList<Student>();
            try {
                Map<String, Object> map = new LinkedHashMap<String, Object>();
                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<Student> dynaSelect(Integer id, String name, Double sal)
                throws Exception {
    
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            List<Student> list = new ArrayList<Student>();
            try {
                Map<String, Object> map = new LinkedHashMap<String, Object>();
    
                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<Integer> 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配置文件

    <?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="
    
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.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-3.0.xsd
      http://www.springframework.org/schema/mvc
      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
      <!-- 1. 配置c3p0连接池 -->
      <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
          <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
          <property name="user" value="wangan"/>
          <property name="password" value="666"/>
      </bean>
    
      <!-- 2. 配置sqlsession代替原生mybatisUtil工具类 -->
      <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
          <!-- 加载配置文件mybatis.xml -->
          <property name="configLocation" value="classpath:mybatis.xml"/>
          <!-- 引入数据资源 -->
          <property name="dataSource" ref="comboPooledDataSource"/>
      </bean>
    
      <!-- 3. mybatis事务管理器,底层用的是jdbc -->
      <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <!-- 引入数据源 -->
          <property name="dataSource" ref="comboPooledDataSource"/>
      </bean>
    
      <!-- 4. 配置事物通知,如何管理事物 -->
      <tx:advice id="tx" transaction-manager="dataSourceTransactionManager">
          <tx:attributes>
              <!-- REQUIRED默认,在有事物情况下执行,没有事物就创建新的事物
                   propagation="REQUIRED" 默认
                   read-only="false"  默认
               -->
              <tx:method name="*" propagation="REQUIRED" read-only="false"/>
          </tx:attributes>
      </tx:advice>
    
      <!-- 5.配置事物切面aop,拦截哪些方法 -->
      <aop:config>
          <aop:pointcut expression="execution(* com.coffee.dao.*.*(..))" id="pointcut"/>
          <aop:advisor advice-ref="tx" pointcut-ref="pointcut"/>
      </aop:config>
    
    
      <!-- 注册dao -->
      <bean id="studentDao" class="com.coffee.dao.StudentDao">
          <property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
      </bean>
      <!-- 注册service -->
      <bean name="studentService" class="com.coffee.service.StudentService">
          <property name="studentDao" ref="studentDao"></property>
      </bean>
    
      <!-- 注册action(注解),里面有service,service加了注解,扫描 -->
      <context:component-scan base-package="com.coffee"/>
    
    
      <!-- 通知springioc注解作用 -->
      <context:annotation-config />
    
    
    
      <!-- 视图解析器 -->
     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="prefix" value="/jsp/"></property>
          <property name="suffix" value=".jsp"></property>
      </bean>
    
    
    </beans>
    

    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

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
      <display-name>sshProject2</display-name>
    
    <!-- struts2 配置 -->
    <filter>
       <filter-name>struts2</filter-name>
         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>struts2</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- spring配置 -->
    <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:bean.xml</param-value>
    </context-param>
    <listener>
    <!-- 服务器启动时自动装配spring的配置bean.xml -->
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    </web-app>
    

    struts.xml

    
    <!-- 拦截器 -->
     <interceptors>
          <interceptor name="userInterceptor" class="com.coffee.action.UserInterceptor"></interceptor>
          <interceptor-stack name="myStack">
              <!-- 配置struts2框架运行时,默认执行自定义拦截器栈 -->
              <interceptor-ref name="defaultStack"></interceptor-ref>
              <!-- 应用自定义拦截器 -->
              <interceptor-ref name="userInterceptor"></interceptor-ref>
          </interceptor-stack>
     </interceptors>
     <!-- 执行指定的拦截器 -->
     <default-interceptor-ref name="myStack"></default-interceptor-ref>
    

    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<Dept> listDept = deptService.getAll();
    
          // 4.数据回显
          // 获取valueStack对象
          ValueStack valueStack = ActionContext.getContext().getValueStack();
          // 移除栈顶元素(旧的)
          valueStack.pop();
          // 入栈,即将更新的值
          valueStack.push(employee);
          request.put("listDept", listDept);
          return "edit";
    
    }
    

    下拉列表

    <td>
        <!-- name="deptId"随便取,代表下拉列表名字 -->
        <s:select list="#request.listDept" listKey="deptId" listValue="deptName" name="deptid" headerKey="-1" headerValue="请选择" value="-1"></s:select>
    </td>
    

    做注册的时候员工的信息联系到另外一张表部门表,下拉菜单选择部门的时候这个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 id="insertList">
    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)
    <foreach close=")" collection="list" item="item" index="index" open="(" separator="union">
    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
    </foreach>
    </insert>
    
    <!-- 分页查询商品,动态sql -->
    <select id="selectPageListUseDys" parameterType="goods" resultMap="goodsResultMap">
    SELECT * FROM (
    SELECT ROWNUM RN,GO.* FROM
    (SELECT * FROM GOODS
    <where>
    <if test="paramEntity.goodsName!=null">AND GOODS_NAME LIKE #{paramEntity.goodsName}</if>
    </where>
    ORDER BY GOODS_ID)GO
    WHERE ROWNUM &lt;= #{start}+#{rows})
    WHERE RN &gt; #{start}
    </select>
    
    

    错误例2:将整个sql语句用<![CDATA[ ]]>

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

    <select id="find" parameterClass="java.util.Map" resultClass="java.lang.Long"
    <![CDATA[ select id   from tableA a,tableB b <dynamic prepend="WHERE">  <isNotNull prepend="AND" property="startDate"
    a.act_time >= #startDate#      and a.act_time <= #endDate#     and a.id = b.id     </isNotNull>
    </dynamic>      ]]>  </select>      正确做法:缩小范围,只对有字符冲突部分进行合法性调整。
    <select id="find" parameterClass="java.util.Map" resultClass="java.lang.Long">     select i
    from tableA a,         tableB b    <dynamic prepend="WHERE">  <isNotNull prepend="AND" property="startDate"> 
    a.act_time >= #startDate# <![CDATA[ and a.act_time <= #endDate#  ]]>     and a.id = b.id 
    </isNotNull>  </dynamic>  </select>
    
    ibatis中应该经常见到<![CDATA[这样的东西吧,它的用处应该是转义一些特殊关键字字符,
    不合法的XML字符必须被替换为相应的实体。 下面是五个在XML文档中预定义好的实体: 
    &lt;                 <       小于号                                            
    &gt;                 >       大于号 
    &amp;                &       和 
    &apos;               '       单引号 
    &quot;               "       双引号 
    

    相关文章

      网友评论

          本文标题:spring mybatis整合

          本文链接:https://www.haomeiwen.com/subject/xidfpftx.html