• Java框架之Mybatis(一)


    一、Mybatis 简介

    Mybatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为Mybatis  , 2013年11月迁移到Github , iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)Mybatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。Mybatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。Mybatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

    二、Mybatis 的执行框架

    1) SqlMapConfig.xml 文件 //名称不一定是这个名称 类似hibernate中的主配置文件

    主配置文件 配置数据源,事务等运行环境,配置映射文件 (xxXmapper.xml... 多个)

    2) SessionFactory

    会话工厂,它是根据配置文件创建的,用来创建  SqlSession

    3) SqlSession

    会话 ,是一个接口,面向用户的接口,主要用来进行数据库操作

    4) Executor

    执行器,是底层封装的一个对象,是一个接口(底层有两个实现,基本执行器,缓存执行器)事实上 SqlSession 的内部就是通过该接口来执行sql语句的

    5) MappedStatement 底层封装的对象,封装sql ,输入参数,输出结果类型等

    三、第一个hello world 程序

    1) 导包

    asm-3.3.1.jar

    cglib-2.2.2.jar

    commons-logging-1.1.1.jar

    javassist-3.17.1-GA.jar

    log4j-1.2.17.jar

    log4j-api-2.0-rc1.jar

    log4j-core-2.0-rc1.jar

    Mybatis-3.2.6.jar

    slf4j-api-1.7.5.jar

    slf4j-log4j12-1.7.5.jar

    2) 在config里建一个配置文件(数据库相关的) mydbconfig.properties , 内容如下

    db.driver=com.mysql.jdbc.Driver
    db.url=jdbc:mysql://localhost:3306/shop
    db.username=admin
    db.password=root

    3) 建立 SqlMapConfig.xml

    <?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>
                    <properties resource="mydbconfig.properties" />
                    
                    <environments default="development">
                        <environment id="development">
                            <transactionManager type="JDBC" />
                            <dataSource type="POOLED">  //POOLED指的是org.apache.ibatis.datasource.pooled.PooledDataSource, 一个数据源的实现类  
                                <property name="driver" value="${db.driver}" />
                                <property name="url" value="${db.url}" />
                                <property name="username" value="${db.username}" />
                                <property name="password" value="${db.password}" />
                            </dataSource>
                        </environment>
                    </environments>
                
                     <mappers>
                        <mapper resource="sqlmap/UserInfo.xml" />
                    </mappers>
                </configuration>   

    4) 编写映射文件 (其实就是bean 对应的映射文件 相当于 hibernate 中的 UsesrInfo.hbm.xml 之类的 )

    命名规则 :

    == UserInfo.xml  //过去的ibatis中

    == 如果使用了mapper 代理  命名规则变为  UserInfoMapper.xml

     //UserInfo.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">  
                    
                    <mapper namespace="test">
                        <select id="getuser_byid"  parameterType="int" resultType="cat.beans.UserInfo" >
                            select * from userInfo where id=#{id}  //如是简单类型,id可以写成任意名字
                        </select>
    </mapper>

    说明: namespace 是命名空间,用来对sql进行隔离 ,注意,如果使用mapper代理的方式开发,它就有特殊的作用

    -- <select id="getuser_byid" ... > 这个id 就是sql的标识,其实将来要封装到 MappedStatement 中

    -- #{ } 代表占位

    --  如是参数是简单类型,{} 中的名字可以任意

    --  resultType 表示返回的java对象的类型,表示要将查询结果映射成什么样的java对象

    5) 在主配置文件中引入这个映射文件

    主配置文件中加入

    <mappers>
             <mapper resource="sqlmap/UserInfo.xml" />
    </mappers>
    //上面的主配置文件中其实已经加入了

    6)测试

    static void test(){
    //加载主配置文件
                InputStream in=Test.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
                //InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");    //Resources是mhybatis 提供的
                    
                SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                SqlSession session =factor.openSession();
                    
                                                       //第一个参数,是sql的id (是映射文件中的statement的id) = 名称空间+sql的id名称 ,
                UserInfo user=session.selectOne("test.getuser_byid",1); //注意,这里的1 不能定成 "1"
                System.out.println(user);
                session.close();        
                }

    在上例的基础上,再添一个模糊查询的例子 

    在 UserInfo.xml 中 加入

    <select id="getuser_biname" parameterType="string" resultType="cat.beans.UserInfo">
    //select * from userInfo where userName  like #{value}   //不行,  它会拼成like '张三'
    select * from userInfo where userName like  '%${value}%'  // ${value} 表示会把传过来的值,直接拼到串上,有可能有sql注入问题,而且
    // 如果parameterType 是简单类型,则${ } 中间的必须写成 value
    </select>
    static void test() throws IOException{
                        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                        SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                        SqlSession session =factor.openSession();
                        
                        UserInfo user=session.selectOne("test.getuser_byid",1); //注意,这里的1 不能定成 "1"
                        System.out.println(user);
                        
                        session.close();
                        
                    }

    总结:

    #{} Mybatis 将  #{} 解释为jdbc PreparedStatement  的一个参数标记  // 就是 select * from t where id= ? 中的 ?

    ${} 将它直接解释为字符串

    理解这两者的区别是很有用的, 因为在某些SQL语句中并不能使用参数标记(parameter markers)。

    那如果有like查询要怎么办呢? 可以这样sql写成第一种 #{} ,传参的时候如下   

    "%张三%"
    selectOne   //返回一个对象
    selectList  //返回一组对象 两者 resultType="cat.beans.UserInfo" 都正常

    在上例的基础上,再增加一个添加用户的功能

    //对于添加这类方法,是没有resultType的
    <insert id="add_user" parameterType="cat.beans.UserInfo"  >
            insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) //后面不要写上分号
    </insert>
            tatic void test3() throws IOException{
                            
                            InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                            SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                            SqlSession session =factor.openSession();
                            
                            UserInfo user=new UserInfo();
                            user.setUserName("陈鹏飞");
                            user.setPassword("admin");
                            user.setNote("这是备注");
                            
                            int result=session.insert("test.add_user",user); 

    // 对于inser,虽然没有为sql声明反回类型,但也能正确的取到反回值的,它是整型 session.commit(); //不要忘了提交事务 System.out.println(result); //能得到正确的值 1 session.close(); }

    在上面的基础上,再添加删除的和修改的功能

    <delete id="deluser_byid" parameterType="int" > 
                        delete from userInfo where id=#{id}
                    </delete>
                    
                    <update id="update_user" parameterType="cat.beans.UserInfo" > <!-- 传过来的userInfo对象中要有id -->
                       update userInfo set userName= #{userName},password= #{password}, note =#{note} where id= #{id}
                    </update>
    //修改
                        static void test4() throws IOException{
        
                            InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                            SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                            SqlSession session =factor.openSession();
                            
                            UserInfo user=session.selectOne("test.getuser_byid",1);
                            user.setUserName("english"); 
                            user.setPassword("englishxxx");
                            user.setNote("englishxxx");
                          int result= session.update("test.update_user",user);
                          session.commit();
                          System.out.println("修改成功: " + result);
                            
                            session.close();
                        }
                        
                     //删除
                        static void test5() throws IOException{
                            InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                            SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                            SqlSession session =factor.openSession();
                            int result= session.delete("test.deluser_byid",10);
                            session.commit();
                            System.out.println("删除成功: " + result);
                            session.close();
                        }

    四、返回自增主键

    mysql 有一个函数 last_insert_id() 可以调用它得到最后一条插入语句生成的自增主键。

    在上面的用户添加的例子上

    <insert id="add_user" parameterType="cat.beans.UserInfo"  >
            <selectKey order="AFTER" keyProperty="id" resultType="int">   //resultType 必填 keyProperty的id 就是userInfo.id
                          select  last_insert_id()
                         //elect new uuid();  //这是mysql生成uui的写法 (32位数字或字母,4位是 -)  如果这样,上面的AFTER要改成before
                         //select 序列名.nextval 这是oracle中的写法
           </selectKey>
                    insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) 
    </insert>

    说明:

    order="AFTER" 指的是 要在这条语句执行之后取得生成的主键,它还有另一个取值 BEFORE

    非自增主键,想取得,要用BEFORE,但生成主键的方式应该是上面的红色的注起来的方式。

    注意,如果用的是后面的方式,则下面的sql要写上id

    例子:生成 uuid型的主键

     <insert id="add_user_new" parameterType="cat.beans.UserInfo"  >
                    <selectKey order="BEFORE" keyProperty="id" resultType="string">   //注意返回类型,注意前面要写成 BEFORE
                        select  uuid()
                    </selectKey>
                    insert into userInfo (id,userName,password,note) values (#{id},#{userName},#{password}, #{note} ) 
                    //注意要把id这列也写上
                </insert>
                
                    UserInfo user=new UserInfo();
                //user.setId() 不用写了,因为主键由Mybatis生成
                    
                    user.setUserName("郑某某");
                    user.setPassword("admin");
                    user.setNote("这是备注");
                    
                    session.insert("test.add_user_new",user);
                    session.commit(); 
        
                    System.out.println(user.getId());  //可以取到主键 369010c6-e631-1033-b927-e281dfdaa6b0

    五、dao层的开发

    SessionFactory 可以做成单例 (未来会交给Spring管理)

    SqlSession  是线程不安全的, 用的时候,要在方法体内 , 这样它就是一个局部变量,千万不要把它写成类成员

    Mybatis 开发DAO 有两种方式

    原始的方式 ,手写dao 和实现类

    //接口 :
    public interface IUserDao {
                        int addUser(UserInfo user);
                        UserInfo getUserById(int id);
                    }
                    
    //实现类
    public class UserDaoImplTest {
                        private IUserDao _dao ;
                        @Before
                        public void setUp() throws Exception {
                            InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                            SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                            _dao=new UserDaoImpl(factor);
                        }
                    
                        @Test
                        public void testAddUser() {
                            UserInfo user=new UserInfo();
                            user.setUserName("周周");
                            user.setPassword("admin");
                            
                            int result=_dao.addUser(user);
                            System.out.println("ok"+result);
                        }
                    
                        @Test
                        public void testGetUserById() {
                            UserInfo user=_dao.getUserById(2);
                            System.out.println(user);
                        }
                    
                    }

    测试用例

    使用 mapper 代理的方式  ,只需要mapper接口 (相当于dao接口)

    public class UserDaoImpl implements IUserDao {
                    private SqlSessionFactory _factory;
                    
                    public UserDaoImpl(SqlSessionFactory factory){
                        this._factory=factory;  //由外界注入 SqlSessionFactory
                    }
                    
                    //添加用户
                    public int addUser(UserInfo user) {
                        SqlSession s =_factory.openSession();
                        int result=s.insert("test.add_user",user);
                        s.commit();
                        return result;
                    }
                
                    //查询用户
                    public UserInfo getUserById(int id) {
                        SqlSession s =_factory.openSession();
                        UserInfo user=s.selectOne("test.getuser_byid",id);
                        s.commit();
                        return user;
                    }
                
                }

    配置文件

    <mapper namespace="test">
                    <select id="getuser_byid"  parameterType="int" resultType="cat.beans.UserInfo" >
                        select * from userInfo where id=#{id} 
                    </select>
                    
                    <insert id="add_user" parameterType="cat.beans.UserInfo"  >
                        <selectKey order="AFTER" keyProperty="id" resultType="int">  
                            select  last_insert_id()
                        </selectKey>
                        insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) 
                    </insert>
                    
                     ... 其他的略
                     
                </mapper>
  • 相关阅读:
    【slenium专题】Webdriver同步设置
    【Selenium专题】WebDriver启动firefox浏览器
    【Selenium专题】WebDriver启动Chrome浏览器(二)
    【Selenium专题】WebDriver启动Chrome浏览器(一)
    Jenkins邮件设置
    Jenkins安装笔记
    for循环输出i为同一值的问题,SetTimeOut
    const、let、var的区别
    浏览器title失去焦点时改变title
    clone对象或数组
  • 原文地址:https://www.cnblogs.com/1693977889zz/p/8227416.html
Copyright © 2020-2023  润新知