zoukankan      html  css  js  c++  java
  • Mybatis学习笔记(三) 之Dao开发

    使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法,常用还是Mapper接口开发。

    SqlSession的使用范围

    public class test1 {
        private static SqlSessionFactory sqlSessionFactory;
        private static Reader reader; 
        //创建会话工厂,传入mybatis的配置文件信息
        static{
            try{
            	//得到配置文件流
                reader = Resources.getResourceAsReader("Configuration.xml");
                //创建会话工厂,传入mybatis的配置文件信息
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);                   
            }catch(Exception e){
                e.printStackTrace();
            }
        }         
        //查询数据
        public void select() {
        	//通过工厂得到sqlsession
            SqlSession session = sqlSessionFactory.openSession();
            try {
            	//通过SqlSession操作数据库//第一个参数:映射文件中statement的id//第二个参数:指定和映射文件所匹配的parameterType类型参数
    	        User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
            } finally {
            	session.close();
            }
        }
    }

    想要通过mabatis对数据库操作,除了要各种配置之外,最终在测试的时候,需要创建特定对象,上图示例:

    1、SqlSessionFactoryBuilder

    SqlSessionFactoryBuilder用于创建SqlSessionFacotySqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

    2、SqlSessionFactory

    SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory

    3、SqlSession

    SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。

    SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

    结论:

    每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

    打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

        	//通过工厂得到sqlsession
            SqlSession session = sqlSessionFactory.openSession();
            try {
            } finally {
              session.close();
            }
    

     原始Dao开发方式

    程序员需要编写DAO和DAO的实现类。需要向DAO实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory来创建SqlSession。

    1、定义Dao接口

    public interface UserDAO{
    
        //根据本id查询用户
        User findUserById(int id) throws Exception;    
        //添加用户
        void insertUser(User user) throws Exception;   
        //根据id删除用户
        void deleteUser(int id) throws Exception;
    }
    

    2、Dao实现类

    DAO实现类
    /**
    * @ClassName: UserDAOImpl 
    * @Description: DAO实现类(注意:SqlSession是非线程安全的,故不能声明为全局的)
     */
    public class UserDAOImpl implements UserDAO {
    
        SqlSessionFactory sqlSessionFactory;
        /**
         * 向DAO实现类中注入SqlSessionFactory(此处通过构造方法注入)
         */
        public UserDAOImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }
        
        @Override
        public User findUserById(int id) throws Exception {
            
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = sqlSession.selectOne("test.findUserById", id);
            sqlSession.close();
            return user;
        }
    
        @Override
        public void insertUser(User user) throws Exception {
            
            SqlSession sqlSession = sqlSessionFactory.openSession();
            sqlSession.insert("test.insertUser", user);
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Override
        public void deleteUser(int id) throws Exception {
            
            SqlSession sqlSession = sqlSessionFactory.openSession();
            sqlSession.delete("test.deleteUser", id);
            sqlSession.commit();
            sqlSession.close();
        }
    
    }
    

    3、新建一个源代码目录命名为test,在UserDAOImpl类中鼠标右键新建一个Junit Test Case,更换源代码目录为test并勾选我们需要测试的方法:

    public class UserDAOImplTest {
    
        private SqlSessionFactory sqlSessionFactory;
        
        /**
         * 此方法在执行测试之前执行,得到一个SqlSessionFactory
         */
        @Before
        public void setUp() throws Exception {
            
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        }
    
        @Test
        public void testFindUserById() throws Exception {
            // 创建UserDAO(在构造中注入SqlSessionFactory)
            UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
            User user = userDAO.findUserById(1);
            System.out.println(user);
        }
    
        @Test
        public void testInsertUser() throws Exception {
            UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
            User user = new User();
            user.setSex("2");
            user.setUsername("孙悟空");
            user.setAddress("方寸灵台山");
            user.setBirthday(new Date());
            userDAO.insertUser(user);
        }
    
        @Test
        public void testDeleteUser() throws Exception {
            UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
            userDAO.deleteUser(27);
        }
    
    }
    

    原始DAO开发中存在的问题

    • DAO的接口实现类中存在大量的模板方法,设想:可以将重复的代码提取出来。

    • 在SqlSession的方法时将Statement的id硬编码在你DAO的实现类中。

    • 调用sqlSession的相关方法传入参数是泛型,即使传入错误的参数,在编译阶段也不会报错,不利于程序员开发。

    Mapper动态代理方式

    实现原理

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

    Mapper接口开发需要遵循以下规范:Mapper可以自动生成Mapper接口实现类代理对象。

    1、 Mapper.xml文件中的namespacemapper接口的类路径相同。

    2、  Mapper接口方法名和Mapper.xml中定义的每个statementid相同

    3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql parameterType的类型相同

    4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sqlresultType的类型相同

    1、UserMapper.xml配置文件

    <?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命名空间,作用就是对sql进行分类化管理,注意:使用mapper代理方法开发,namespace有特殊重要作用 -->
    <mapper namespace="com.yihaomen.mybatis.dao.IUserOperation">
    	<!-- 在映射文件中配置很多sql -->
    	<!-- id标识映射文件的sql,称为statement的id ,将sql语句封装到mappedStatement对象中,所以将id称为statement的id
    	parameterType:指定输入类型  resultType:指定sql输出结果的所映射的java对象,select指定resultType表示将单挑记录
    	映射成java对象-->
        <select id="selectUserByID" parameterType="int" resultType="User">
            select * from `user` where id = #{id}
        </select>
        
        <insert id="addUser" parameterType="User" 
            useGeneratedKeys="true" keyProperty="id"> 
            insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})  
        </insert>  
        
        <update id="updateUser" parameterType="User">
            update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}
        </update>
        
        <delete id="deleteUser" parameterType="int">
            delete from user where id=#{id}
        </delete>
        
        <select id="list"  resultType="User">
            select * from `user`
        </select>
        
        <!-- ${}表示拼接sql串,指定就是单挑记录所映射的java对象类型,使用${}拼接,容易导致sql注入
        ${value}:拼接输入参数的内容,如果传入类型是简单类型,${}中只能使用value -->
        <select id="findUserByName"  parameterType="String"  resultType="User">
            select * from `user` where username like '%${value}%'        
        </select>
    </mapper>

    2、UserMapper.java类

    package com.yihaomen.mybatis.dao;
    
    import java.util.List;
    
    import com.yihaomen.mybatis.model.Article;
    import com.yihaomen.mybatis.model.User;
    
    //注意:接口名字必须与  xml中的namespace名字一样   2、接口实现方法每个名字  与xml中的id对应
    public interface IUserOperation {   
    	//查询数据
        public User selectUserByID(int id);    
        //增加数据
        public void addUser(User user);   
        //更新数据
        public void updateUser(User user);    
        //删除数据
        public void deleteUser(int id);
        //联合查询
        public List<Article> getUserArticles(int id);    
        //list获取
        public List<User> list();    
        //模糊查询
        public List<User> findUserByName(String name);
        
    }
    

    完成前面2步之后不要忘了在映射文件SqlMapConfig.xml中加载UserMapper.xml哦!

    <!-- 配置映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml"/>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
    

    3、针对UserMapper接口测试

    package com.yihaomen.mybatis.ui;
    
    import java.io.Reader;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import com.yihaomen.mybatis.dao.IUserOperation;
    import com.yihaomen.mybatis.model.User;
    
    public class Test {
        private static SqlSessionFactory sqlSessionFactory;
        private static Reader reader; 
    
        //创建会话工厂,传入mybatis的配置文件信息
        static{
            try{
            	//得到配置文件流
                reader = Resources.getResourceAsReader("Configuration.xml");
                //创建会话工厂,传入mybatis的配置文件信息
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
                        
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        //公共方法,返回初始化的sqlSessionFactory对象
        public static SqlSessionFactory getSession(){
            return sqlSessionFactory;
        }
        
        //查询数据
        public void select() {
        	//通过工厂得到sqlsession
            SqlSession session = sqlSessionFactory.openSession();
            try {
            	//通过SqlSession操作数据库
            	//第一个参数:映射文件中statement的id
            	//第二个参数:指定和映射文件所匹配的parameterType类型参数
    	        User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
    	        System.out.println(user.getUserAddress());
    	        System.out.println(user.getUserName());
            } finally {
            	session.close();
            }
        }
        
        //增加数据
        public void addUser(String address,String name){
        	//创建user对象
            User user=new User();
            user.setUserAddress(address);
            user.setUserName(name);
            user.setUserAge(80);
            
            //通过工厂得到SqlSession
            SqlSession session = sqlSessionFactory.openSession();
            try {
                IUserOperation userOperation=session.getMapper(IUserOperation.class);
                //添加数据
                userOperation.addUser(user);
                //提交
                session.commit();
                //System.out.println("当前增加的用户 id为:"+user.getId());
            } finally {
                session.close();
            }
        }
        
        //更新数据
        public void updateUser(int id,String address){
            //先得到用户,然后修改,提交。
            SqlSession session = sqlSessionFactory.openSession();
            try {
                IUserOperation userOperation = session.getMapper(IUserOperation.class);
                User user = userOperation.selectUserByID(id);            
                user.setUserAddress(address);
                userOperation.updateUser(user);
                session.commit();
                System.out.println("更新成功!!");
            } finally {
                session.close();
            }
        }
        
        //删除数据
        public void deleteUser(int id) {
        	SqlSession session = sqlSessionFactory.openSession();
        	
        	try{
        		IUserOperation userOperation = session.getMapper(IUserOperation.class);
                userOperation.deleteUser(id);
                session.commit();  
                System.out.println("删除数据:id= "+id);
        	}finally {
                session.close();
            }
    		
    	}
        
        //list获取
        public void getList() {
        	SqlSession session = sqlSessionFactory.openSession();
        	
        	try{
        		IUserOperation userOperation = session.getMapper(IUserOperation.class);
        		List<User> us = userOperation.list();    		
        		session.commit();  
                //System.out.println("生成list: "+us.size());
        	}finally {
                session.close();
            }
    		
    	}
        
        //模糊查询
        public void geFindUserByName(String name) {
        	SqlSession session = sqlSessionFactory.openSession();
        	
        	try{
        		IUserOperation userOperation = session.getMapper(IUserOperation.class);
        		List<User> us = userOperation.findUserByName(name);   
        		System.out.println(us.size());
        		session.commit();  
        		
        	}finally {
                session.close();
            }
    		
    	}
    
    
    	public static void main(String[] args) {
    		Test test = new Test();
    		//test.getList();		
    		test.geFindUserByName("小");
    		//test.addUser("杭州","小江");
    
    
    	    }
    
            
    }
    
    • 我们比较疑问的就是我们在UserMapper.xml的根据用户名查找用户的ResultType使用的是普通的POJO,但是我们自己的Mapper接口中返回值是List类型。这不就造成了类型不一致么?但是,实际上代理对象内部调用了selectOne()或者selectList(),代理对象内部会自动进行判断是否是单独的POJO选用合适的方法。

    • Mapper接口中方法的参数只有一个是否会影响系统的维护?DAO层的代码是被业务层公用的,即使Mapper接口的参数只有一个我们也可以使用包装的POJO来满足系统需求。

    • 注意:持久层中方法的参数中可以使用包装类型,但是Service层中不建议使用包装类型(不利于业务层的拓展维护)。

      

  • 相关阅读:
    2.vi 和 vim 编辑器
    1.Linux文件及目录结构
    关于聚集表的学习
    一个完整的表维护程序
    转换函数CONVERSION_EXIT_TSTRN_OUTPUT
    ABAP常用字符串处理
    函数中的异常参数设计
    数据元素文本增强(修改标准数据元素描述)
    锁对象的维护
    在物理表中分配搜索帮助
  • 原文地址:https://www.cnblogs.com/airsen/p/6273016.html
Copyright © 2011-2022 走看看