(二)Mybatis介绍

(一)Mybatis介绍

Hibernate与Mybatis的区别

Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。适用于需求变化不多的项目,比如后台管理系统,OA等.
Mybatis:专注于sql本身,需要程序员自己编写sql语句,sql修改,优化比较方便,虽然程序员需要自己写sql,mybatis也可以实现映射(输入映射,输出映射)
Hibernate的开发难度要大于Mybatis。主要由于Hibernate比较复杂、庞大,学习周期较长。而Mybatis则相对简单一些,并且Mybatis主要依赖于sql的书写,让开发者感觉更熟悉。

原始dao的开发方法

(1)SqlSession的使用范围

  • SqlsessionFactory创建SqlSession,使用单例模式管理工厂类
  • SqlSession是一个面向用户(程序员)接口,SqlSession中提供了很多操作数据库的方法,SqlSession是线程不安全的,所以最佳应用场合在方法体内,定义成局部变量

(2)原始dao的开发方法(程序员需要写dao接口以及实现类)

//dao接口
import java.util.List;
import com.zb.entity.Student;

public interface StudentDao {

    //通过id查询学生信息
    public Student queryStudentById(int id);
    //通过姓名模糊查询
    public List<Student> queryStudentByName(String name);
    //添加
    public int insertStudent(Student student);
    //修改
    public int updateStudent(Student student);
    //删除
    public int deletStudent(int id);
}
//dao的实现类
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.zb.entity.Student;

public class StudentDaoImpl implements StudentDao {

    //通过构造函数将我们SqlsessionFactory注入到这里
    private SqlSessionFactory factory;

    public StudentDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    //Sqlsession  是线程不安全的,他的应用场景是在方法中
    @Override
    public Student queryStudentById(int id) {
        //第一步:创建sqlsession
        SqlSession session = factory.openSession();

        Student student = session.selectOne("test.queryStudentById",id);

        //释放资源
        session.close();
        return student;
    }

    @Override
    public List<Student> queryStudentByName(String name) {
        SqlSession session = factory.openSession();

        List<Student> students = session.selectList("test.queryStudentByName", "%张%");

        session.close();
        return students;
    }

    @Override
    public int insertStudent(Student student) {
        SqlSession session = factory.openSession();

        int count = session.insert("test.addStudent",student);

        //提交事务
        session.commit();
        //释放资源
        session.close();

        return count;
    }

    @Override
    public int updateStudent(Student student) {
        SqlSession session = factory.openSession();


        int count = session.update("test.updateStudent", student);

        //提交事务
        session.commit();
        //释放资源
        session.close();

        return count;
    }

    @Override
    public int deletStudent(int id) {
        SqlSession session = factory.openSession();

        int count = session.delete("test.deleteStudentById",id);

        session.commit();
        session.close();
        return count;
    }

}

写一个工具类,创建单例的sqlSessionFactory对象

import java.io.IOException;
import java.io.InputStream;

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

public class FactoryUtil {

    private static SqlSessionFactory factory;
    //synchronized  同步锁   同一时间只能一个线程调用这个方法   
    //线程安全  非线程安全
    public static synchronized SqlSessionFactory getFactory() throws IOException {
        if (factory == null) {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            factory = new SqlSessionFactoryBuilder().build(is);
        }
        return factory;
    }
}

主类测试

public class Test {

    public static void main(String[] args) throws IOException {

        //------------------------Dao层的查询------------------------------
        SqlSessionFactory factory = FactoryUtil.getFactory();//先获得一个
        StudentDao studentDao = new StudentDaoImpl(factory);

        Student student = studentDao.queryStudentById(3);
        System.out.println(student);
        //---------------------------------------------------------------



        //------------------------Dao层的插入------------------------------
        SqlSessionFactory factory = FactoryUtil.getFactory();
        StudentDao studentDao = new StudentDaoImpl(factory);

        Student student2 = new Student();
        student2.setName("2222");
        student2.setAge(18);
        student2.setClass_id(2);

        System.out.println(studentDao.insertStudent(student2));
        //---------------------------------------------------------------


        //------------------------Dao层的修改(需要结合查询)------------------------------
        SqlSessionFactory factory = FactoryUtil.getFactory();
        StudentDao studentDao = new StudentDaoImpl(factory);

        Student student = studentDao.queryStudentById(10);
        student.setClass_id(21);

        System.out.println(studentDao.updateStudent(student));
        //---------------------------------------------------------------


        //------------------------Dao层的删除------------------------------
        SqlSessionFactory factory = FactoryUtil.getFactory();
        StudentDao studentDao = new StudentDaoImpl(factory);

        studentDao.deletStudent(6);
        //---------------------------------------------------------------

        }
}

(3)总结:
1、接口Dao
2、实现类Impl
3、Sqlsessionfactory单例的工具类
4、测试
缺点 :代码重复;错误无法在编译时发现
因为这些缺点,所以引出 mapper代理

Mapper代理的方法(程序员只需要写Mapper的接口,Mapper来当作接口实现类)

  1. Mapper.xml中,namespace要等于mapper接口的地址
  2. 接口中的方法名等于mapper.xml中标签statement的id
  3. Mapper接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
  4. Mapper接口中的方法数返回值类型和mapper.xml中statement的resultType指定的类型一致
  5. Mapper.xml起名规范:实体类名(如Student)+Mapper.xml

Mapper代理的好处 :
代码不重复;错误在编译时能知道~比如:参数是object类型对象,在传统中dao开发中参数不对应检测不出来,只能在运行的时候检测出来;用了mapper之后,只要参数类型不对应,在编译的时候就能查出来,就会提示错误。

创建一个StudentMapper接口,此接口就相当于dao接口

public interface StudentMapper {

    //通过id查询学生信息
    public Student queryStudentById(int id);
    //通过姓名模糊查询
    public List<Student> queryStudentByName(String name);
    //添加
    public int addStudent(Student student);
    //修改
    public int updateStudent(Student student);
    //删除
    public int deletStudentById(int id);    
}

编写StudentMapper.xml
需要注意的地方,图片中已表明。
这里写图片描述

主类测试

public class Test {

    public static void main(String[] args){
        //使用mapper代理的方式开发
        SqlSessionFactory sessionFactory = FactoryUtil.getFactory();
        //开启session
        SqlSession session = sessionFactory.openSession();
        //生成mapper接口实现类的代理对象
        StudentMapper mapper = session.getMapper(StudentMapper.class);

        //-------------------查询-----------------------
        Student student = mapper.queryStudentById(2);
        System.out.println(student);
        //-------------------增加-----------------------
        Student student = new Student();
        student.setName("啊啊");
        student.setAge(18);
        student.setClass_id(2);
        mapper.addStudent(student);
        session.commit();
        session.close();
}

Mapper代理对象内部调用selectOne或者SelectList

1) 如果mapper方法返回的是单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库
2) 如果mapper方法返回的集合对象,代理对象内部通过SelectList查询数据库

Mapper接口方法参数只能有一个是否影响系统开发?

mapper接口只能有一个参数,因为在xml中单个标签只能有一个parameterType,所以就限定了方法中的参数中能有一个。
解决办法:就是使用包装类,即包装类的属性包括其他类的对象或其他类型的数据。包装类其实就是给原来的类增添一些属性,如现有一个学生类,属性有姓名name,id,班级class_id,年龄age等,那么创建一个新的类叫做Studentgrade,它继承了student,额外的属性有分数等等。

Mapper 是如何实现的不用实现类的?

通过namespace 反射 得到 接口 ,通过接口中的方法名去找标签中的id,找到了对应的id,就去执行标签中的操作。根据返回类型 是pojo 还是集合 来决定是用selectOne还是selectList。

Mybatis-config.xml文件

对于java项目,在Mybatis-config.xml中必须要配置的有2个
(1) 数据源
(2)加载xml文件

(1)数据源

<properties resource="db.properties"></properties>
<environments default="development">  
        <environment id="development"> 
         <!-- 使用jdbc事务管理,事务由mybatis控制 -->  
            <transactionManager type="JDBC" />  
         <!-- 数据库连接池,由mybatis管理 --> 
            <dataSource type="POOLED">  
                <property name="driver" value="${jdbc.driverClass}" />  
                <property name="url" value="${jdbc.url}" />  
                <property name="username" value="${jdbc.username}" />  
                <property name="password" value="${jdbc.password}" />  
            </dataSource>  
        </environment>  
    </environments>   

注意:
如果不加第一句话,那么你必须把内容写在mybatis-config.xml中,建议还是加上第一句话,即把数据库连接放在properties里,这样体现了功能分离的特点,以后修改也方便。
附上properties文件:

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/数据库名?characterEncoding=UTF-8
jdbc.username=填写自己的账号名
jdbc.password=填写自己的密码

(2)加载xml文件
有两种方式:

  • 第一种就是非Mapper开发
  • 第二种就是Mapper开发
<mappers>
    <!-- 第一种 填写相对路径 非Mapper开发的xml的名字没有要求-->
    <mapper resource="student.xml" />
    <!-- 第二种:
        使用规范:
        1、mapper接口的名字要与mapper.xml文件的名字保持一致,并且在同一个文件夹中
        2、必须使用mapper代理的方式开发!
    -->
    <mapper class="com.zb.Mapper.StudentMapper"/>
</mappers>

Mybatis-config.xml文件中还可以写的内容
(1)定义别名
意思就是:在放sql语句的xml中,parameterType和resultType需要写全路径名,有了别名之后就可以直接写别名。

定义别名分2种:

  • 为某个类单独定义别名
  • 为包底下的所以的类定义别名,即批量定义别名
<!-- 定义别名 -->
<typeAliases>
        <!-- 单独定义别名 -->
        <!-- <typeAlias type="com.zb.entity.Student" alias="student"/> -->

        <!-- 批量定义别名 -->
        <!-- package 是扫描的包的名字 
            自动扫描指定的包,为包下的类去自动设置别名,别名就是类名  大小写无所谓
        -->
        <package name="com.zb.entity"/>
</typeAliases>

补充:
其实int,double,String在放sql语句的xml中也需要写全路径名,但是它们是mybatis默认支持的别名。(mybatis默认支持的别名如下图)
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值