mybatis相似于hibernate,都是简化对数据库操做的框架,可是和hibernate不一样的是,mybatis更加灵活,总体来讲框架更小,这体如今它须要咱们手写SQL语句,而hibernate则将对数据库的操做对程序员彻底透明了,程序员只须要按照面向对象的思想编写代码便可,想要看sql语句,就必须在配置文件中声明java
<property name="show_sql">true</property>
hibernate对数据库的操做封装的很是完全,所以灵活性不高,mybatis可以实现相似于hibernate的功能,可是须要本身写sql语句,这并不表示使用mybatis更加繁琐,相反的,我的认为mybatis框架很小,配置起来也很是简单,mybatis真正优秀的地方在哪里,为何它会愈来愈火?mysql
mybatis官方给出的mybatics 3.1.1文档中有这么一段话说出了为什么mybatis这么火的缘由:git
其中文意思大概就是:Mybatis提供的完整功能集可以经过使用基于“映射语言”的XML来实现,这正是Mybatis流行这么多年的缘由。程序员
以上内容是mybatis中的“映射文件”相关的内容,从这段话中不难看出。Mybatis的核心是“映射文件”,经过该映射文件可以实现Mybatis的全部功能。其形式如上所示。github
练习项目源代码:https://github.com/kdyzm/day79_1_mybatisdemospring
和hibernate有些类似,Mybatis中也有两种配置文件,一种配置文件是“总的配置文件”,相似于hibernate中的hibernate.cfg.xml,名字随意,可是最好起一个比较规范的名字,可以见名知意,我习惯使用mybatis-config.xml命名。在mybatis 3.1.1文档中有详细的使用说明,其提供了最简单的使用形式:sql
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 <environments default="development"> 7 <environment id="development"> 8 <transactionManager type="JDBC" /> 9 <dataSource type="POOLED"> 10 <property name="driver" value="${driver}" /> 11 <property name="url" value="${url}" /> 12 <property name="username" value="${username}" /> 13 <property name="password" value="${password}" /> 14 </dataSource> 15 </environment> 16 </environments> 17 <mappers> 18 <mapper resource="org/mybatis/example/BlogMapper.xml" /> 19 </mappers> 20 </configuration>
配置文件的位置任意,可是推荐放到classpath路径下,文档中说明该文件能够放到任意位置,在windows下可使用file:///协议直接访问,可是我没试过。数据库
以上内容很是简单,将对应的变量替换掉,接下来就是配置所谓的“映射文件”BlogMapper.xml。apache
映射文件的写法和形式以下:windows
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="org.mybatis.example.BlogMapper"> 6 <select id="selectBlog" parameterType="int" resultType="Blog"> 7 select * from Blog where id = #{id} 8 </select> 9 </mapper>
一样这也是文档中给出的例子,固然,这是最简单的例子,可是全部的配置文件中都须要对其进行配置,能够说是最核心并且是最基础的配置方式了。
说明:
namespace属性:命名空间,该命名空间的值任意,可是必须保证在整个项目中惟一,对应一个实体如Student,必定要有一个惟一的命名空间,因此这里直接取该实体的类名便可。
mapper标签中的内容是全部对数据库操做的sql语句。这里的select标签表示里面的呃sql语句是查询语句,若是是update标签,表示是更新语句......
id属性:该属性表示惟一,这天然没必要说,可是该属性只是在当前Mapper标签中惟一便可。在引用该sql语句的时候,直接使用namespace+.+id来表示。
parameterType:参数类型,这里表示的是#{id}中的id对应的参数类型。
resultType:结果集类型,若是是Student,则不该当直接写上Student,而应当写上com.kdyzm.domain.Student,这里可以直接写上Blog是由于该Blog是已经声明了的“引用类型”。引用的写法以后再说。
和hibernat相同,mybatis的CRUD操做都依赖于一个Session对象,可是该对象在mybatis中有了新名字,名为SqlSession,并且建立它使用的工厂名字也再也不是SessionFactory,而是SqlSessionFactory,示例代码以下:
获取SqlSessionFactory对象的方式:
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
获取SqlSession对象的方式:
SqlSession session = sqlSessionFactory.openSession();
以后就是使用Session对象的使用问题了。
下载相关jar包并加入classpath,过程略,下载地址:https://github.com/mybatis/mybatis-3/releases
为了方便查看控制台输出使用的log4j的配置文件:
1 log4j.rootLogger=DEBUG, Console 2 #Console 3 log4j.appender.Console=org.apache.log4j.ConsoleAppender 4 log4j.appender.Console.layout=org.apache.log4j.PatternLayout 5 log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n 6 log4j.logger.java.sql.ResultSet=INFO 7 log4j.logger.org.apache=INFO 8 log4j.logger.java.sql.Connection=DEBUG 9 log4j.logger.java.sql.Statement=DEBUG 10 log4j.logger.java.sql.PreparedStatement=DEBUG
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 <environments default="development"> 7 <environment id="development"> 8 <transactionManager type="JDBC" /> 9 <dataSource type="POOLED"> 10 <property name="driver" value="com.mysql.jdbc.Driver" /> 11 <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> 12 <property name="username" value="root" /> 13 <property name="password" value="5a6f38" /> 14 </dataSource> 15 </environment> 16 </environments> 17 <mappers> 18 <mapper resource="com/kdyzm/domain/Student.xml"/> 19 <mapper resource="com/kdyzm/domain/Person.xml"/> 20 <mapper resource="com/kdyzm/domain/Clazz.xml"/> 21 </mappers> 22 </configuration>
总的配置文件中并无什么实质性的东西,最核心的配置都在“映射文件”中。
1 package com.kdyzm.domain; 2 3 public class Student { 4 private Integer id; 5 private String name; 6 private String password; 7 private Integer age; 8 private Clazz clazz; 9 /*************************** 分割线 ******************************************/ 10 public Integer getId() { 11 return id; 12 } 13 14 public void setId(Integer id) { 15 this.id = id; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public String getPassword() { 27 return password; 28 } 29 30 public void setPassword(String password) { 31 this.password = password; 32 } 33 34 public Integer getAge() { 35 return age; 36 } 37 38 public void setAge(Integer age) { 39 this.age = age; 40 } 41 42 public Clazz getClazz() { 43 return clazz; 44 } 45 46 public void setClazz(Clazz clazz) { 47 this.clazz = clazz; 48 } 49 50 @Override 51 public String toString() { 52 return "Student [id=" + id + ", name=" + name + ", password=" + password + ", age=" + age + "]"; 53 } 54 }
1 package com.kdyzm.domain; 2 3 public class Person { 4 private int personId; 5 private String personName; 6 private String personAge; 7 /****************************华丽的分割线***************************************/ 8 public int getPersonId() { 9 return personId; 10 } 11 public void setPersonId(int personId) { 12 this.personId = personId; 13 } 14 public String getPersonAge() { 15 return personAge; 16 } 17 public void setPersonAge(String personAge) { 18 this.personAge = personAge; 19 } 20 public String getPersonName() { 21 return personName; 22 } 23 public void setPersonName(String personName) { 24 this.personName = personName; 25 } 26 @Override 27 public String toString() { 28 return "Person [personId=" + personId + ", personName=" + personName + ", personAge=" + personAge + "]"; 29 } 30 }
1 package com.kdyzm.domain; 2 3 import java.util.List; 4 5 public class Clazz { 6 private int id; 7 private String name; 8 private String desc; 9 private List<Student> students; 10 /*************************华丽的分割线************************/ 11 public int getId() { 12 return id; 13 } 14 public void setId(int id) { 15 this.id = id; 16 } 17 public String getName() { 18 return name; 19 } 20 public void setName(String name) { 21 this.name = name; 22 } 23 public String getDesc() { 24 return desc; 25 } 26 public void setDesc(String desc) { 27 this.desc = desc; 28 } 29 public List<Student> getStudents() { 30 return students; 31 } 32 public void setStudents(List<Student> students) { 33 this.students = students; 34 } 35 @Override 36 public String toString() { 37 return "Clazz [id=" + id + ", name=" + name + ", desc=" + desc + "]"; 38 } 39 }
用的最多的两个类是Student和Clazz,Person类基本上没用上。
com.kdyzm.domain.Student.xml配置文件中的mapper标签:
<mapper namespace="com.kdyzm.domain.Student"></mapper>
<select id="selectUserById" parameterType="int" resultMap="com.kdyzm.domain.Student"> select s.* ,c.* from student s,clazz c where s.clazz=c.clazzid and s.studentid=#{id}; </select>
java代码:
Student student=session.selectOne("com.kdyzm.domain.Student.selectUserById", "1");
<select id="selectAllStudent" resultType="com.kdyzm.domain.Student"> select * from Student </select>
java代码:
Collection<Student> students=sqlSession.selectList("com.kdyzm.domain.Student.selectAllStudent");
<insert id="insertIntoStudent" parameterType="com.kdyzm.domain.Student"> insert into student(studentid,name,password,age) values(#{id},#{name},#{password},#{age}) </insert>
java代码:
1 String statement="com.kdyzm.domain.Student.insertIntoStudent"; 2 Student student=new Student(); 3 student.setId(7); 4 student.setName("张三"); 5 student.setAge(13); 6 student.setPassword("xiaozhang"); 7 int result=session.insert(statement, student); 8 session.commit();
这里必定不要忘了提交的动做:commit();
<update id="updateStudentByStudentObject" parameterType="com.kdyzm.domain.Student"> update student set name=#{name},password=#{password},age=#{age} where studentid=#{id} </update>
<delete id="deleteUserById" parameterType="string"> delete from student where studentid = #{id} </delete>
(1)常用parameterType类型为string或者int类型做为id对一个对象进行操做,常常传入一个对象的类型如com.kdyzm.domain.Student对一个对象进行修改操做,可使用HashMap类型来替换对象类型,这时候类型值就须要写上hashMap。
(2)返回值是一个对象仍是一个对象的集合,返回值类型都是同一种,若是是普通对象类型,那么以Student为例就是com.kdyzm.domain.Student,若是是HashMap类型,那么就是hashMap。
若是parameterType类型是基本数据类型或者String类型,那么在sql中的#{id}中的id名字能够任意写,只是起着占位符的做用,可是若是是对象类型的话,则名字就须要和对象中的属性名彻底相同才行,由于须要调用对象的get方法获取字段的值。
解决方法有两种:
select id as studentId,name as studentName from student
可是使用这种方式有一个很是明显的缺点,那就是针对每一次查询都必须这么写,显得很是乱并且书写起来很是的不方便,还容易出错,致使的直接后果就是效率低下。
使用第二种方式可以解决这种麻烦。
<!-- 使用ResultMap标签解决数据库中表的字段和类中的属性字段不一致的状况 --> <resultMap type="com.kdyzm.domain.Person" id="personMap"> <id column="id" property="personId"/> <result column="name" property="personName"/> <result column="age" property="personAge"/> </resultMap>
其中column中填写数据库表中的列名,property中填写对应对象中的字段名。
在hibernate中咱们常用关联关系查询,好比查到了Student对象以后直接就可以获取Clazz对象,获取了Clazz对象以后直接就可以获得List<Student>对象,一样,在mybatis中也能欧作到这一点,这里先不考虑懒加载的事情。
这里使用Student和Clazz为例说明
Clazz和Student之间是一对多的关系,如今的需求就是根据Clazz对象获取全部的Student对象。
能够利用以前提到的resultMap标签实现这一点,首先须要在Clazz类中有List<Student>students成员变量,同时提供对应的set/get方法;而后进行映射文件中的XML文件的配置:
1 <resultMap type="com.kdyzm.domain.Clazz" id="clazzMap"> 2 <id property="id" column="clazzid"></id> 3 <result property="name" column="name" /> 4 <result column="describtion" property="desc" /> 5 <collection property="students" ofType="com.kdyzm.domain.Student"> 6 <id column="studentid" property="id"></id> 7 <result column="name" property="name" /> 8 <result column="password" property="password" /> 9 <result column="age" property="age" /> 10 </collection> 11 </resultMap>
和以前不太相同的是添加了黄色背景部分的内容。
property属性对应着类中的字段名称,ofType属性是集合中的元素类型。collection标签的子标签是ofType类型中的全部成员变量,固然虽然Student类中有Clazz类型的成员变量,可是这里不要写上,除此以外全部的成员变量都要写上。
sql查询的方式也要修改,这里必须是两表联合查询才行,同时将resultType改为resultMap:
1 <select id="selectClazzById" resultMap="clazzMap" parameterType="int"> 2 select s.*,c.* from student s,clazz c where c.clazzid =#{id} and s.clazz=c.clazzid 3 </select>
java代码:
1 String statement = "com.kdyzm.domain.Clazz.selectClazzById"; 2 Clazz clazz = session.selectOne(statement, "1"); 3 List<Student> students = clazz.getStudents(); 4 for (Student student : students) { 5 System.out.println(student); 6 }
Student对象和Clazz对象之间是多对一的关系,如今的需求就是须要根据Student对象获取其对应的Clazz对象。
这里仍是须要借助于resultMap标签:
1 <resultMap type="com.kdyzm.domain.Student" id="studentMap"> 2 <id column="studentid" property="id"></id> 3 <result column="name" property="name"/> 4 <result column="password" property="password"/> 5 <result column="age" property="age"/> 6 <association property="clazz" javaType="com.kdyzm.domain.Clazz"> 7 <id property="id" column="clazzid"></id> 8 <result property="name" column="name"/> 9 <result column="describtion" property="desc" /> 10 </association> 11 </resultMap>
固然了,最关键的仍是以上黄色背景部分的内容,这里使用association标签完成任务。
property属性填写的是对象中的相应字段,javaType对应的是其java类型。而后association标签内填写该对象中的全部属性和表中字段的对应关系,注意,全部的必定都要填写完整,不然没有填写完整的部分对应的字段就会是NULL类型。
固然,查询的sql语句也必须改变,改为两张表的联合查询:
<!-- 根据UserId查询User对象的查询方法 --> <select id="selectUserById" parameterType="int" resultMap="studentMap"> select s.* ,c.* from student s,clazz c where s.clazz=c.clazzid and s.studentid=#{id}; </select>
java代码以下:
String statement = "com.kdyzm.domain.Student.selectUserById"; Student student = session.selectOne(statement, "1"); System.out.println(student.getClazz());