mybatis

mybatis

第一章 介绍
1. 三层架构
  界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
  业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
  数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。


三层对应的包
  界面层: controller包 (servlet)
  业务逻辑层: service 包(XXXService类)
  数据访问层: dao包(XXXDao类)


三层中类的交互
  用户使用界面层--> 业务逻辑层--->数据访问层(持久层)-->数据库(mysql)


三层对应的处理框架
  界面层---servlet---springmvc(框架)
  业务逻辑层---service类--spring(框架)
  数据访问层---dao类--mybatis(框架)


2.框架
  框架是一个舞台, 一个模版

模版:
  1. 规定了好一些条款,内容。
  2. 加入自己的东西

框架是一个模块
  1.框架中定义好了一些功能。这些功能是可用的。
  2.可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。


框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。

框架特点:
  1. 框架一般不是全能的, 不能做所有事情
  2. 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
  3. 框架是一个软件

 

mybatis框架
一个框架,早期叫做ibatis, 代码在github。
mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
  1)sql mapper :sql映射
    可以把数据库表中的一行数据 映射为 一个java对象。
    一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据

  2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。


mybatis提供了哪些功能:
  1. 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
  2. 提供了执行sql语句的能力, 不用你执行sql
  3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力
    while (rs.next()) {
      Student stu = new Student();
        stu.setId(rs.getInt("id"));
        stu.setName(rs.getString("name"));
        stu.setAge(rs.getInt("age"));
        //从数据库取出数据转为 Student 对象,封装到 List 集合
        stuList.add(stu);
      }
  4.提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet


开发人员做的是: 提供sql语句
最后是: 开发人员提供sql语句--mybatis处理sql---开发人员得到List集合或java对象(表中的数据)

总结:
  mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC,
  使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet
  的创建,销毁,sql的执行。

 

第二章:主要类介绍
1 主要类的介绍
  1) Resources: mybatis中的一个类, 负责读取主配置文件
      InputStream in = Resources.getResourceAsStream("mybatis.xml");

  2)  SqlSessionFactoryBuilder : 创建SqlSessionFactory对象,
      SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
       //创建SqlSessionFactory对象
       SqlSessionFactory factory = builder.build(in);

  3)SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
    在整个项目中,有一个就够用了。

    SqlSessionFactory:接口 , 接口实现类: DefaultSqlSessionFactory
    SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();

    openSession()方法说明:
    1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
    2. openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
      openSession(false) 非自动提交事务的SqlSession对象


  4)SqlSession:
    SqlSession接口 :定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
    SqlSession接口的实现类DefaultSqlSession。

  使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
  在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。

  代码部分 

 1  //测试方法
 2     @Test
 3     public void testInsert() throws IOException {
 4         //访问,mybatis获取student数据
 5         //1.定义mybatis主配置文件的名称,从根目录开始
 6         String config="mybatis.xml";
 7         //读取这个config表示的内容
 8         InputStream in= Resources.getResourceAsStream(config);
 9         //3.创建SqlSessionFactoryBuilder对象
10         SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
11         //4,创建SqlSessionFactory对象
12         SqlSessionFactory factory=builder.build(in);
13         //5.{重要}获取SqlSession对象,从SqlSessionFactory获取SqlSession
14         SqlSession sqlSession=factory.openSession();
15         //6.{重要}执行要执行的sql语句的标识,sql映射文件中的namespace+"."+标识的id
16         String sqlId="com.rzpt.dao.StudentDao"+"."+"insertstudent";
17         //7.执行sql语句,通过sqlId找到语句
18         Student student=new Student();
19         //student.setId(4);
20         student.setName("张飞");
21         student.setEmail("zhangfei@qq.com");
22         student.setAge(33);
23         int nums = sqlSession.insert(sqlId,student);
24 
25         //mybatis默认不是自动提交事务的,所以在insert,update,delete之后要手动提交事务
26         sqlSession.commit();
27         //8.输出结果
28         System.out.println("执行insert的结果="+nums);
29         //9.关闭sqlSession
30         sqlSession.close();
31     }
View Code

第三章:动态代理
1. 动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
2. 传入参数: 从java代码中把数据传入到mapper文件的sql语句中。
  1)parameterType : 写在mapper文件中的 一个属性。 表示dao接口中方法的参数的数据类型
    例如StudentDao接口
    public Student selectStudentById(Integer id)

       

  parameterType他的值是java类型数据类型的全限定名称或mybatis定义的别名
   例如:parameterType="java.lang.Integer"
或: parameterType="int"
    不是强制的,mybatis通过反射可以自己获取,一般不用写

  2) 一个简单类型的参数
  简单类型: mybatis把java的基本数据类型和String都叫简单类型。
  在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}

  接口:public Student selectStudentById(Integer id)
    mapper:select id,name, email,age from student where id=#{studentId}

  3) 多个参数,使用@Param命名参数
  接口 public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
  使用 @Param("参数名") String name
  mapper文件:
  <select>
    select * from student where name=#{myname} or age=#{myage}
  </select>

  

   

  4) 多个参数,使用java对象
    语法 #{属性名}

    vo: value object , 放一些存储数据的类。比如说 提交请求参数, name ,age
    现在想把name ,age 传给一个service 类。

    vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。

    pojo: 普通的有set, get方法的java类。 普通的java对象

    Servlet --- StudentService( addStudent( MyParam param) )

    entity(domain域): 实体类, 和数据库中的表对应的类,

    (1).

定义方法,多个参数,利用java对象作为方法的参数
* 使用对象语法:
* #{属性名,javaType=类型名称,jdbcType=数据类型} 很少用
* javaType=类型名称,在java中的数据类型
* jdbcType=数据类型,在数据库的数据类型
* 例如:#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
* 简化:#{属性名},上述mybatis反射机制会自动获取,不用提供

     

     

     (2).多个参数-简单类型,按位置查询  

      mybatis.3.4之前,使用#{0},
   mybatis.3.4之后,使用#{arg0},
    

    

     (3).多个参数,使用Map存放多个值

    

     

  5) # 和 $

    select id,name, email,age from student where id=#{studentId}
    # 的结果: select id,name, email,age from student where id=?


    select id,name, email,age from student where id=${studentId}
    $ 的结果:select id,name, email,age from student where id=1001

    String sql="select id,name, email,age from student where id=" + "1001";
    使用的Statement对象执行sql, 效率比PreparedStatement低。


   $:可以替换表名或者列名, 你能确定数据是安全的。可以使用$ 

  

         

   

# 和 $区别
  1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
  2. #能够避免sql注入,更安全。
  3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
  4. $有sql注入的风险,缺乏安全性。
  5. $:可以替换表名或者列名


3. mybatis的输出结果
mybatis执行了sql语句,得到java对象。

  1)resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。
    resultType结果类型的它值

       1. 类型的全限定名称

       2. 类型的别名, 例如 java.lang.Integer别名是int

处理方式:
  1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
  2. mybatis把ResultSet指定列值付给同名的属性。


  <select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
    select id,name, email,age from student
  </select>

  对等的jdbc
    ResultSet rs = executeQuery(" select id,name, email,age from student" )
    while(rs.next()){
      Student student = new Student();
      student.setId(rs.getInt("id"));
      student.setName(rs.getString("name"))
    }

  2) 定义自定义类型的别名
    1)在mybatis主配置文件中定义,使<typeAlias>定义别名
    2)可以在resultType中使用自定义别名


  3)resultMap:结果映射, 指定列名和java对象的属性对应关系。
    1)你自定义列值赋值给哪个属性
    2)当你的列名和属性名不一样时,一定使用resultMap


  resultMap和resultType不要一起用,二选一

       代码部分

 1     //Dao
 2     //返回一个值
 3     int countStudent();
 4     //返回map
 5     Map<Object,Object> selectMapById(Integer id);
 6     //使用resultMap定义映射关系
 7     List<Student> selectAllStudents();
 8     //列名和属性名不一致时,第一种方法
 9     List<MyStudent> selectAllMyStudents();
10     //列名和属性名不一致,第二种方法
11     List<MyStudent> selectDiffColProperty();
12     //第一种模糊查询,在java代码中指定 like的内容
13     List<Student> selectLikeOne(String name);
14     //第二种方式,name就是李值,在mapper中拼接 like "%"李"%"
15     List<Student> selectLikeTwo(String name);
 1   <!--sql执行后返回一行一列-->  <!--resultType="int" 全限定名称,也可以是 resultType="java.lang.Integer"-->
 2     <select id="countStudent" resultType="int">
 3         select count(*) from student
 4     </select>
5 <!--返回Map 6 1)列名是map的key,列值是map的value 7 2)只能最多返回一行记录,否则会报错 8 --> 9 <select id="selectMapById" resultType="java.util.HashMap"> 10 select id,name,age from student where id=#{stuid} 11 </select>
12 <!--使用resultMap 13 1)先定义resultMap 14 2)在select标签,使用resultMap来引用1的定义 15 --> 16 <!--定义resultMap 17 id:自定义名称 18 type:java类型全限定名称 19 --> 20 <resultMap id="studentMap" type="com.rzpt.domain.Student"> 21 <!--列名和属性的关系--> 22 <!--主键列,使用id标签--> 23 <id column="id" property="id"/> 24 <!--非主键列--> 25 <result column="name" property="name"/> 26 <result column="email" property="email"/> 27 <result column="age" property="age"/> 28 </resultMap> 29 <select id="selectAllStudents" resultMap="studentMap"> 30 select id,name,email,age from student 31 </select> 32 33 <!--列名和属性名不一致时--> 34 <resultMap id="MyStudentMap" type="com.rzpt.domain.MyStudent"> 35 <!--列名和属性的关系--> 36 <!--主键列,使用id标签--> 37 <id column="id" property="stuId"/> 38 <!--非主键列--> 39 <result column="name" property="stuName"/> 40 <result column="email" property="stuEmail"/> 41 <result column="age" property="stuAge"/> 42 </resultMap> 43 <select id="selectAllMyStudents" resultMap="MyStudentMap"> 44 select id,name,email,age from student 45 </select> 46 <!--列名和属性名不一致,第二种方法 47 resultType原则是同名的列值赋值给同名的属性值 48 所有使用列别名(java对象的属性名) 49 --> 50 <select id="selectDiffColProperty" resultType="com.rzpt.domain.MyStudent"> 51 select id as stuId,name as stuName,email as stuEmail,age as stuAge from student 52 </select>
53 <!-- 第一种 like java代码中指定 like内容--> //
String name="%刘%";
54    <select id="selectLikeOne" resultType="com.rzpt.domain.Student">
55     select id,name,email,age from student where name like#{name}
56   </select>
57 <!-- 第二种 like,name就是李值,在mapper中拼接 like "%" 李" %"--> 58 <select id="selectLikeTwo" resultType="com.rzpt.domain.Student"> 59 select id,name,email,age from student where name like "%" #{name} "%" 60 </select>

第四章 动态sql
动态sql: sql的内容是变化的,可以根据条件获取到不同的sql语句。
主要是where部分发生变化。

动态sql的实现,使用的是mybatis提供的标签, <if> ,<where>,<foreach>

  1)<if>是判断条件的,
    语法<if test="判断java对象的属性值">
        部分sql语句
      </if>

  2)<where> 用来包含 多个<if>的, 当多个if有一个成立的, <where>会自动增加一个where关键字,
    并去掉 if中多余的 and ,or等。

  3)<foreach> 循环java中的数组,list集合的。 主要用在sql的in语句中。
    学生id是 1001,1002,1003的三个学生

    select * from student where id in (1001,1002,1003)

   


  4)sql代码片段, 就是复用一些语法
    步骤
    1.先定义 <sql id="自定义名称唯一"> sql语句, 表名,字段等 </sql>
    2.再使用, <include refid="id的值" />

  代码部分 

 1     //Dao
 2     //动态sql,使用java对象作为参数 and
 3     List<Student> selectStudentIf(Student student);
 4     //动态sql,or
 5     List<Student>selectStudentIfOr(Student student);
 6 
 7     //where
 8     List<Student>selectStudentWhere(Student student);
 9     //foreach 用法1 集合放简单类类型
10     List<Student> selectForeachOne(List<Integer> idlist);
11     //foreach,用法2,集合放对象
12     List<Student> selectForeachTwo(List<Student> stulist);
13     //使用PageHelper分页数据
14     List<Student> selectAll();
 1 <mapper namespace="com.rzpt.dao.StudentDao">
 2     <!--自定义sql片段-->
 3     <sql id="studentSql">
 4         select id,name,email,age from student
 5 
 6     </sql>
 7 
 8     <!--if
 9         <if.test+"使用参数java对象的属性值作为判断条件,语法为:属性=xxx值"
10     -->
11     <select id="selectStudentIf" resultType="com.rzpt.domain.Student">
12         /*select id,name,age,email from student*/
13         <include refid="studentSql"/>
14         where
15         <if test="name != null and name !=''">
16             name=#{name}
17         </if>
18         <if test="age>0">
19             and age>#{age}
20         </if>
21     </select>
22     <!--1=1 的作用是防止一端出现不满足的情况下sql语句错误 where会弥补这个问题-->
23     <select id="selectStudentIfOr" resultType="com.rzpt.domain.Student">
24         select id,name,age,email from student
25         where id>0
26         <if test="name != null and name !=''">
27             name=#{name}
28         </if>
29         <if test="age>20">
30             or age>#{age}
31         </if>
32     </select>
33 
34     <!--where 会自动删除多余的语句-->
35     <select id="selectStudentWhere" resultType="com.rzpt.domain.Student">
36         select id,name,age,email from student
37         <where>
38             <if test="name != null and name !=''">
39                 name=#{name}
40             </if>
41             <if test="age>20">
42                 or age>#{age}
43             </if>
44         </where>
45 
46     </select>
47 <!--foreach使用,List放简单数据类型<Integer>--> 48 <select id="selectForeachOne" resultType="com.rzpt.domain.Student"> 49 select * from Student where id in 50 <!-- 51 collection:表示接口中的方法参数的类型,如果是数组使用array,如何是list使用list 52 item:自定义的表示数组和集合成员的变量 53 open:循环开始的字符 54 close:循环结束的字符 55 separator:集合成员之间的分割符 56 --> 57 <foreach collection="list" item="myid" open="(" close=")" separator=","> 58 #{myid} 59 </foreach> 60 </select>
61 <!--foreach使用,List放对象--> 62 <select id="selectForeachTwo" resultType="com.rzpt.domain.Student"> 63 select * from Student where id in 64 <foreach collection="list" item="stu" open="(" close=")" separator=","> 65 #{stu.id} 66 </foreach> 67 </select> 68 <!--selectAll 分页,查询所有--> 69 <select id="selectAll" resultType="com.rzpt.domain.Student"> 70 select * from student order by id 71 </select> 72 </mapper>

测试代码:

  1 //动态sql
  2     @Test
  3     public void testSelectStudentIf() {
  4         SqlSession sqlSession = MyBatisUtils.getSqlSession();
  5         StudentDao dao = sqlSession.getMapper(StudentDao.class);
  6         Student student=new Student();
  7         student.setName("刘备");
  8         student.setAge(20);
  9         List<Student> students = dao.selectStudentIf(student);
 10         for (Student stu:students){
 11             System.out.println("if...and"+stu);
 12         }
 13     }
 14     //or
 15     @Test
 16     public void testSelectStudentIfOr() {
 17         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 18         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 19         Student student=new Student();
 20         //name为条件不满足会提示sql语句错误,需要在sql语句加一个恒成立的式子
 21         student.setName("");
 22         student.setAge(34);
 23         List<Student> students = dao.selectStudentIfOr(student);
 24         for (Student stu:students){
 25             System.out.println("if...or"+stu);
 26         }
 27     }
 28     //where
 29     @Test
 30     public void testSelectStudentWhere() {
 31         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 32         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 33         Student student=new Student();
 34         //name为条件不满足会提示sql语句错误,需要在sql语句加一个恒成立的式子
 35         //student.setName("张三");
 36         student.setAge(34);
 37         List<Student> students = dao.selectStudentWhere(student);
 38         for (Student stu:students){
 39             System.out.println("where"+stu);
 40         }
 41     }
 42     //以前的拼接,现在有foreach完成
 43     @Test
 44     public void testfor(){
 45         List<Integer> list=new ArrayList<>();
 46         list.add(1001);
 47         list.add(1002);
 48         list.add(1003);
 49         String sql ="select * from student where id in";
 50         StringBuilder sb=new StringBuilder();
 51         sb.append("(");
 52         for (Integer i:list){
 53             sb.append(i).append(",");
 54         }
 55         //删除末尾
 56         sb.deleteCharAt(sb.length()-1);
 57         sb.append(")");
 58         sql=sql+sb.toString();
 59         System.out.println("拼接的sql"+sql);
 60     }
 61     //foreach 集合里面是基本数据类型
 62     @Test
 63     public void testSelectForeachOne() {
 64         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 65         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 66         List<Integer> list=new ArrayList<>();
 67         list.add(1);
 68         list.add(2);
 69         list.add(3);
 70         List<Student> students = dao.selectForeachOne(list);
 71         for (Student stu:students){
 72             System.out.println("foreach"+stu);
 73         }
 74     }
 75     //foreach  集合里面是对象
 76     @Test
 77     public void testSelectForeachTwo() {
 78         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 79         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 80         List<Student> stuList=new ArrayList<>();
 81         Student s1=new Student();
 82         s1.setId(4);
 83         stuList.add(s1);
 84         s1=new Student();
 85         s1.setId(5);
 86         stuList.add(s1);
 87         List<Student> students = dao.selectForeachTwo(stuList);
 88         for (Student stu:students){
 89             System.out.println("foreach"+stu);
 90         }
 91     }
 92     //分页
 93     @Test
 94     public void testSelectAll() {
 95         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 96         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 97         //加入PageHelper的方法,分页
 98         //pageNum:第几页
 99         //pageSize:一页有多少数据
100         PageHelper.startPage(3,3);
101         List<Student> students = dao.selectAll();
102         for (Student stu:students){
103             System.out.println("分页"+stu);
104         }
105     }
测试代码

第五章:配置文件
1. 数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。 和mybatis主配置文件分开。
目的是便于修改,保存,处理多个数据库的信息。

  1)在resources目录中定义一个属性配置文件, xxxx.properties ,例如 jdbc.properties
    在属性配置文件中, 定义数据,格式是 key=value
    key: 一般使用 . 做多级目录的。
    例如 jdbc.mysql.driver , jdbc.driver, mydriver
       jdbc.driver=com.mysql.jdbc.Driver
       jdbc.url=jdbc:mysql//.....
       jdbc.username=root
       jdbc.password=123456

                        

       

  2)在mybatis的主配置文件,使用<property> 指定文件的位置
    在需要使用值的地方, ${key}

2.mapper文件,使用package指定路径
  

 1 <mappers>
 2         <!--第一种方式,指定多个mapper文件位置-->
 3         <mapper resource="com/rzpt/dao/StudentDao.xml"/>
 4         <!--第二种方式,使用包名
 5             name:xml文件所在的包名,这个包名所有的xml文件一次一次都能加载给mybatis
 6                 1.mapper文件名称需要和接口名称一样,区分大小写
 7                 2.mapper文件和dao接口在同一目录
 8         -->
 9        <!-- <package name="com.rzpt.dao"/>-->
10     </mappers>
View Code

第六章:PageHelper

  PageHelper做数据分页的。

 1 //分页
 2     @Test
 3     public void testSelectAll() {
 4         SqlSession sqlSession = MyBatisUtils.getSqlSession();
 5         StudentDao dao = sqlSession.getMapper(StudentDao.class);
 6         //加入PageHelper的方法,分页
 7         //pageNum:第几页
 8         //pageSize:一页有多少数据
 9         PageHelper.startPage(3,3);
10         List<Student> students = dao.selectAll();
11         for (Student stu:students){
12             System.out.println("分页"+stu);
13         }
14     }
原文地址:https://www.cnblogs.com/yumu77/p/13956506.html