zoukankan      html  css  js  c++  java
  • MyBatis(二)

    一、输入输出映射

    1、输入类型parameterType

    1.1 传递基本类型

    1.2 传递POJO对象

    使用ONGL表达式解析对象字段的值,#{}或者${}中的值为POJO属性的名称  user.username

    1.3 传递POJO包装对象QueryVo

    查询条件是多个查询条件的综合

    1.3.1 QueryVo

    public class QueryVo {
    
        private User user;
    
        public User getUser() {
            returnuser;
        }
    
        publicvoid setUser(User user) {
            this.user = user;
        }
    }

    1.3.2 UserMapper.xml

    <!-- 使用包装类型查询用户 使用ognl从对象中取属性值,如果是包装对象可以使用.操作符来取内容部的属性
        -->
        <select id="findUserByQueryVo" parameterType="com.guojie.pojo.QueryVo" resultType="user">
            SELECT * FROM user where username like '%${user.username}%' and sex=#{user.sex}  // 查询条件为多个时,入参类型需要为POJO
    parameterType
    </select>

    1.3.3 UserMapper接口中

    public List<User> findUserByQueryVo(QueryVo vo);

    1.3.4 测试

    @Test
    public void testFindUserByQueryVo() throws Exception {
         SqlSession sqlSession = sessionFactory.openSession();
         //获得mapper的代理对象,通过getMapper方法实例化接口
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //创建QueryVo对象 QueryVo queryVo = new QueryVo(); //创建user对象 User user = new User(); user.setUsername("刘"); user.setSex("1"); queryVo.setUser(user);
    //根据queryvo查询用户 List<User> list = userMapper.findUserByQueryVo(queryVo); System.out.println(list); sqlSession.close();
    }

     

    2、输出类型resultType

    2.1 输出基本类型

    2.1.1 UserMapper.xml

    <!-- 获取用户列表总数 -->
        <select id="findUserCount" resultType="int">
           select count(*) from user
        </select>

    2.1.2 UserMapper接口

    public int findUserCount() throws Exception;

    2.1.3 测试

    Public void testFindUserCount() throws Exception{
        //获取session
        SqlSession session = sqlSessionFactory.openSession();
        //获取mapper接口实例
        UserMapper userMapper = session.getMapper(UserMapper.class);
    
        int count = userMapper.findUserCount();
            
        //关闭session
        session.close();
    }

    2.2 输出POJO对象

    2.3 输出POJO列表

    3、resultMap(用List可取代)

    resultType需要POJO属性和sql查询的列名一致才能将查询结果映射为POJO,自动映射

    resultMap在POJO属性和sql查询的列名不一致时也行,可用于映射复杂类型的POJO,需要手动配置

    <select id="selectOrderList" resultMap="orders">
         select user_id, user_name from user
    </select>
    <resultMap type="Orders"  id="orders">
         <result column="user_id" property="userId">
    </resultMap>

    id:结果集的唯一标识

    property:POJO类的属性

    column:sql字段

    二、动态sql

    通过MyBatis提供的各种标签方法实现动态拼接sql

     1、<if>&<where>

    <select id="findUserByNameAndSex" parameterType="cn.guojie.pojo.User" resultType="cn.guojie.pojo.User">
      <where>
          <if test="username!=null and username!=' ' ">
              and username like '%${username}%'
          </if>
          <if test="sex!=null and sex!=' ' ">
              and sex=#{sex}
          </if>
      <where>
    </select>

    where作用:添加where关键字,去掉第一个条件的and关键字

    条件中username为POJO的属性

     

    2、sql片段<sql>

    提取重复的sql条件封装重用

    <sql id="userFileds">
        重复代码
    </sql>
    <select>
      <!--调用sql条件 -->
        <include refid="userField" />
    </select>

     

    3、<foreach>

    向sql传数组或list

    <select id="findUserByIds" parameterType="cn.guojie.pojo.QueryVo" resultType="com.guojie.pojo.User">
        <where>
            <!-- ids为QueryVo中的List集合属性 -->
            <if test="ids"!=null>
                <foreach collection="ids" item="id" open="id in ("  close=")“ seperator="," ”>
                    #{id}
                </foreach>
            </if>
        </where>
    </select>

    等同于select * from user whereid in (1, 2, 3)

    collection:传入的集合变量名

    item:循环的数据存入变量

    open:开始拼接的字符串

    close:结束拼接的字符串

    seperator:分隔符

    sql中不要有or,会造成性能下降,用in

    @Test
    public void testFindUserByIds() throws Execption {
      SqlSession openSession = factory.openSession();
      // 通过getMapper方法实例化接口
      UserMapper mapper =  openSession.getMapper(UserMapper.class);
      
      QueryVo vo = new QueryVo();  
      List<Integer> ids = new ArrayList<Integer>();
      ids.add(1);
      ids.add(2);
      ids.add(3);
      vo.setIds(ids);
    
      List<User> list = mapper.findUserByIds(vo);
    }    

    三、关联查询

    多中有一的属性引用,一中有多的集合引用

    1、一对一查询

    以订单为中心,单个订单只能属于一个用户,相对用户一对一,订单表以用户表的id为外键

    互联网一般单表查询多,关联查询较少

    1.1 方式一:自动映射(常用) resultType

    根据表的字段名和POJO类中的属性名对应

    select a.*, b.id uid, username, birthday, sex, address 
    from orders a, user b
    where a.userId = b.id

    1.1.1 自定义OrdersCustom

    包含用户和订单中所有属性或者继承Orders类,再加上User类的属性

    public class OrdersCustom extends Orders {
    
        private String username;// 用户名称
        private String address;// 用户地址
            setter&getter;
    }
    <!-- 查询所有订单信息 -->
    <select id="findOrdersList" resultType="cn.guojie.mybatis.pojo.OrdersCustom">
        select a.*, b.id uid, username, birthday, sex, address 
        from orders a, user b
        where a.user_id = b.id
    </select>
    public void testfindOrdersList() throws Exception{
         //获取session
         SqlSession session = sqlSessionFactory.openSession();
         //获取mapper接口实例
         UserMapper userMapper = session.getMapper(UserMapper.class);
         //查询订单信息
         List<OrdersCustom> list = userMapper.findOrdersList();
         System.out.println(list);
         //关闭session
         session.close();
    }

     

    1.2 方式二:手动映射(MyBatis官方)  resultMap

    指定表中字段名和POJO类中的属性名的对应关系

    用association完成关联查询

    1.2.1 在Orders类中加入User对象

    private User user;

    1.2.2 OrderMapper.xml中

    <!-- 查询订单关联用户信息使用resultmap -->
        <resultMap type="cn.guojie.pojo.Orders" id="orderUserResultMap">
             <!-- id为主键字段,column为表字段,property为POJO属性,result为非主键字段 -->
            <id column="id" property="id"/>
            <result column="user_id" property="userId"/>
            <result column="number" property="number"/>
            <result column="createtime" property="createtime"/>
            <result column="note" property="note"/>
            <!-- 一对一关联映射 -->
            <!-- 
            为Order中增加的user对象设置对应关系
            property : Orders对象的user属性
            javaType:user属性对应的类型
             -->
            <association property="user" javaType="cn.guojie.pojo.User">
                <!-- column:user表的主键对应的列  property:user对象中id属性-->
                <id column="user_id" property="id"/>
                <result column="username" property="username"/>
                <result column="address" property="address"/>
            </association>
        </resultMap>
    <select id="findOrdersList" resultMap="orderUserResultMap">
        select a.*, b.id uid, username, birthday, sex, address 
        from orders a, user b
        where a.user_id = b.id
    </select>

    1.2.3 OrderMapper接口中

    public List<Orders> findOrdersList();

     1.2.4 测试

    public void testfindOrdersListResultMap() throws Exception{
         //获取session
         SqlSession session = sqlSessionFactory.openSession();
         //获取mapper接口实例
         UserMapper userMapper = session.getMapper(UserMapper.class);
    
         //查询订单信息
         List<Orders> list = userMapper.findOrdersList();
       System.out.println(list);
       //关闭session  
       session.close();
     }

     2、一对多查询

    以用户为中心,一个用户对应多个订单

    只能手动映射,在User类中加入Order的List<Orders>集合

    private List<Orders> orderList;
    <resultMap type="cn.guojie.pojo.user" id="userOrderResultMap">
            <!-- 用户信息映射 -->
            <id column="id property="id" "/>
            <result column="username property="username" "/>
            <result column="birthday property="birthday" "/>
            <result column="sex property="sex" "/>
            <result column="address property="address""/>
    
            <!-- 
            一对多关联映射 集合对象关系映射 
           property:将数据放入User对象中的orderList属性中
           ofType:指定orderList属性的泛型类型
             -->
            <collection property="orders" ofType="cn.guojie.pojo.Orders">
              <id column="oid property="id" "/>    
                <!--用户id已经在user对象中存在,此处可以不设置-->
                <!-- <result  column="id property="userId""/> -->
                <result column="number property="number" "/>
                <result column="createtime property="createtime" "/>
                <result  column="note property="note""/>
            </collection>
        </resultMap>
            
    <select id="finUserAndOrders" resultMap="userOrderResultMap">
          select a.*, b.id oid, number,createtime
          from user a, order b 
          where a.id = b.user_id
    </select> 
    public List<User> findUserAndOrders();
    @Test
    public void testFindUserAndOrders() {
        SqlSession session = sqlSessionFactory.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<User>result = userMapper.getUserOrderList();
        for (User user : result) {
            System.out.println(user);
        }
        session.close();
    }

    四、Spring整合MyBatis

    1、思路

    (1)数据库连接池及其事务管理应交给Spring容器管理

    (2)SqlSessionFactory工厂对象应该放到Spring容器中作为单例对象

    (3)传统DAO开发中,应从Spring容器中获得sqlSession对象;Mapper动态代理形式中,应从Spring容器中获得mapper的接口代理对象

    2、整合

    2.1 导包

    Spring 、MyBatis、Spring+MyBatis整合包、MySQL数据库驱动包、数据库连接池DBCP(比C3P0效率低)

    2.2 Spring核心配置文件applicationContext.xml

    <?xml version="1.0"encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
        <!-- 加载配置文件 -->
        <context:property-placeholder location="classpath:db.properties"/>
        <!-- 数据库连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
            <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="10"/>
            <property name="maxIdle" value="5"/>
        </bean>
        <!-- mapper配置 -->
        <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 数据库连接池 -->
            <property name="dataSource" ref="dataSource"/>
            <!-- 加载mybatis的全局配置文件 -->
            <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
        </bean>
    </beans>

    Spring容器配置文件需要加classpath

    db.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=root

    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>
            <package name="cn.guojie.mybatis.pojo"/>
        </typeAliases>
        <mappers>
            <mapperresource="sqlmap/User.xml"/>
        </mappers>
    </configuration>

    3、原生DAO

    接口+实现类,实现类继承自SqlSessionSupport类,提供getSqlSession()来获取SqlSession

    需要在Spring配置文件中指定DAO类

    DAO实现类需要继承SqlSessionDaoSupport超类

    在DAO实现类中不要手动关闭会话,不要提交事务

    applicationContext.xml中

    <!-- 配置UserDao实现类 -->
    <bean id="userDao" class="cn.guojie.dao.UserDaoImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    DAO实现类

    public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
    
        @Override
        public User findUserById(int id) throws Exception {
            SqlSession session = this.getSqlSession();
            User user = session.selectOne("test.findUserById", id);
            //不能关闭SqlSession,让spring容器来完成
            //session.close();
            return user;
        }
    
        @Override
        public void insertUser(User user) throws Exception {
            SqlSession session = this.getSqlSession();
            session.insert("test.insertUser", user);
            session.commit();
            //session.close();
        }
    }

    测试

    public class UserDaoTest {
        private ApplicationContext applicationContext;
        @Before
        public void setUp() throws Exception{
        String configLocation = "classpath:spring/ApplicationContext.xml";
        //初始化spring运行环境
        applicationContext = new ClassPathXmlApplicationContext(configLocation);
        }
    
        @Test
        public void testFindUserById() throws Exception {
        UserDao userDao = (UserDao) applicationContext.getBean("userDao");
        User user = userDao.findUserById(1);
        System.out.println(user);
        }
    }

    4、Mapper接口动态代理

    只需要接口,由MyBatis生成其实现类

    applicationContext.xml中

    方式一

    <!-- 配置mapper代理对象 -->
    <bean id=userMapper class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!-- 配置mapper接口全路径名-->
        <property name="mapperInterface" value="cn.guojie.mybatis.mapper.UserMapper"/>            
        <propertyname="sqlSessionFactory"ref="sqlSessionFactory"></property>
    </bean>
    public class UserMapperTest {
    
        private ApplicationContext applicationContext;
    
        @Before
        publicvoid setUp() throws Exception {
            applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
        }
    
        @Test
        public void testGetUserById() {
            UserMapper userMapper = applicationContext.getBean(UserMapper.class);
            User user = userMapper.getUserById(1);
            System.out.println(user);
        }
    
    }

    方式二:包扫描批量引入Mapper(常用

    <!-- 使用扫描包的形式来创建mapper代理对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="cn.guojie.mybatis.mapper"></property>
    </bean>

    每个mapper代理对象的id就是类名,扫描后引用时首字母小写

    SqlMapConfig.xml中<package name="cn.guojie.mapper"/>包扫描批量引入接口可以不要了,重复引用

    五、MyBatis逆向工程

    1、导包

    MyBatis核心包

    数据库驱动

    逆向工程包

    日志包log4j-1.2.16.jar

    2、generator.xml   工程目录下

    (1)POJO所在的包路径注意修改

    (2)添加要生成的数据库表

    (3)mapper文件和接口所在的包路径要一致

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
      PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
      "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
        <context id="testTables" targetRuntime="MyBatis3">
            <commentGenerator>
                <!-- 是否去除自动生成的注释 true:是 : false:否 -->
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
            <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
                password="admin">
            </jdbcConnection>
            <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
                connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" 
                userId="yycg"
                password="yycg">
            </jdbcConnection> -->
    
            <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 
                NUMERIC 类型解析为java.math.BigDecimal -->
            <javaTypeResolver>
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
    
            <!-- targetProject:生成POJO类的位置 -->
            <javaModelGenerator targetPackage="cn.guojie.pojo"
                targetProject=".src">
                <!-- enableSubPackages:是否让schema作为包的后缀 -->
                <property name="enableSubPackages" value="false" />
                <!-- 从数据库返回的值被清理前后的空格 -->
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
            <!-- targetProject:mapper映射文件生成的位置,和接口放在同一目录 -->
            <sqlMapGenerator targetPackage="cn.guojie.mapper" 
                targetProject=".src">
                <!-- enableSubPackages:是否让schema作为包的后缀 -->
                <property name="enableSubPackages" value="false" />
            </sqlMapGenerator>
            <!-- targetPackage:mapper接口生成的位置 和映射文件放在同一目录 -->
            <javaClientGenerator type="XMLMAPPER"
                targetPackage="cn.guojie.mapper" 
                targetProject=".src">
                <!-- enableSubPackages:是否让schema作为包的后缀 -->
                <property name="enableSubPackages" value="false" />
            </javaClientGenerator>
            <!-- 指定数据库表 -->
    <!--         <table tableName="items"></table> -->
            <table tableName="orders"></table>
    <!--         <table tableName="orderdetail"></table> -->
            <table tableName="user"></table>
            <!-- <table schema="" tableName="sys_user"></table>
            <table schema="" tableName="sys_role"></table>
            <table schema="" tableName="sys_permission"></table>
            <table schema="" tableName="sys_user_role"></table>
            <table schema="" tableName="sys_role_permission"></table> -->
            
            <!-- 有些表的字段需要指定java类型
             <table schema="" tableName="">
                <columnOverride column="" javaType="" />
            </table> -->
        </context>
    </generatorConfiguration>

    3、使用Java类生成mapper文件(mapper接口+mapper.xml+POJO类)

    public class StartServer {
        
        public void generator() throws Exception{
            List<String> warnings = new ArrayList<String>();
            boolean overwrite = true;
            File configFile = new File("genarator.xml"); 
            ConfigurationParser cp = new ConfigurationParser(warnings);
            Configuration config = cp.parseConfiguration(configFile);
            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                    callback, warnings);
            myBatisGenerator.generate(null);
        }
    
        public static void main(String[] args) throws Exception {
            try {
                StartServer startServer = new StartServer();
                startServer.generator();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    生成文件的方式是追加而不是覆盖,运行第二次会再生成一遍,要删除原来的再生成,不然会报错

    4、拷贝生成的文件

    mapper xml文件和mapper.java文件在一个目录内且文件名相同

    5、测试

    public class UserMapperTest {
        private ApplicationContext applicatonContext;
        
        @Before
        public void setUp() throws Exception{
            String configLocation = "classpath:ApplicationContext.xml";
            applicatonContext = new ClassPathXmlApplicationContext(configLocation);
        }
            
        @Test
        public void testFindUserById() throws Exception{
            UserMapper userMapper = (UserMapper)applicatonContext.getBean("userMapper");
            
            User user = userMapper.selectByPrimaryKey(1);
            System.out.println(user);
        }
        
        @Test
        public void testFindUserAndSex() throws Exception{
            UserMapper userMapper = (UserMapper)applicatonContext.getBean("userMapper");
            
            //创建UserExample对象
            UserExample userExample = new UserExample();
            //通过UserExample对象创建查询条件封装对象(Criteria中是封装的查询条件)
            Criteria createCriteria = userExample.createCriteria();
            
            //加入查询条件
            createCriteria.andUsernameLike("%王%");
            createCriteria.andSexEqualTo("1");
            
            List<User> list = userMapper.selectByExample(userExample);
            System.out.println(list);
        }
    }

    like模糊查询时要加%

    POJO:不按MVC分层,只有JavaBean的一些属性和setter&getter

    Domain:不按MVC分层,只有JavaBean的一些属性和setter&getter

    PO:用于持久层,在增加或者修改的时候,从页面直接传入action中,其中JavaBean类名等于表名,属性名等于字段名,还有对应的setter&getter

    VO:View Object表现层对象,主要用于在高级查询中从页面接收传过来的各种条件参数,好处是扩展性强

    BO:在Service,现在基本不用

    有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
  • 相关阅读:
    未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”中加载类型“System.ServiceModel.Activation.HttpModule”。
    服务代理的关闭与并发会话的限制
    批量插入数据利器之SqlBulkCopy
    VS 生成 dll、exe 版本号与SVN版本号一致
    DataTable / DataSet 与 xml 的相互转换
    C# 操作嵌入的资源
    【WCF安全】使用X509证书自定义验证
    预先生事件和后期生成命令事件
    (转)利用WPF的ListView进行大数据量异步加载
    (转)SQL知识_SqlParameter数组
  • 原文地址:https://www.cnblogs.com/1989guojie/p/7691272.html
Copyright © 2011-2022 走看看