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 }
第三章:动态代理
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>
第六章: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 }