Mybatis框架使用总结:
首先简单总结一下Mybatis使用的原理:
Mybatis就是一个框架,将连接数据库并查询的操作等全部交给框架进行操作
实现的方法就是配置一系列的xml文件
首先关注一个关键的SQLMapperConfig.xml文件,当然文件名字是可以更改的,这个xml文件主要定义两个东西:数据库的连接配置和mapper映射文件
数据库的连接配置注意两点:
一、environment表示的是数据库的环境,该环境可以定义好多个,但是只能使用一个。比如
<environments default="mysql">
<environment id="mysql">
...
</environment>
<environment id="oracle">
...
</environment>
</environments>
我在标签里面定义了很多个environment,有mysql,有oracle等等,但是我default设定的是mysql,因此使用mysql
二、DataSource的设定有两种--pooled与unpooled,表示是不是用连接池,,使用连接池效率会更高,因此无脑选择pooled就是了
mapper映射文件则是配置映射文件的位置,具体的映射文件中定义的是一系列的sql语句,用于查询
下面可以简单想象一下执行的步骤:
首先是读取SQLMapperConfig.xml文件的内容作为输入流(意思是读取配置文件,根据文件中的标签让Mybatis进行环境的配置)
接着使用构建者模式创建一个builder
让builder根据输入流建造一个工厂
再使用工厂模式创建一个事务Session
Session是具体操作数据库的,但是要操作哪个表呢?因此要将设定的mapper给加载进来
一个mapper有一个namespace,namespace代表的就是数据库中的某一个表,一个表在Java中被抽象为一个类,因此将类加载进来就好,常用的加载方式就是读取字节码文件,也就是用反射***.class
现在就完成了所有的初始化操作
下面是具体的操作数据库:
前面提到了mapper的工作空间是一个表,一个表对应一个被抽象出来的类,但是我们还没有定义操作,比如查询,更新?因此我们需要定义一个操作类,这些操作在Java中是用函数来表示的。在不用Mybatis的时候我们采用的方式是在类中定义一组具体的方法,而使用了Mybatis我们还定义类中的具体方法就体现不出Mybatis的优势了
Mybatis将该方法优化为定义一个操作接口即可,操作接口中定义一组抽象方法,在实际使用的时候我们加载字节码文件就是加载这个接口的字节码文件
比如我们定义了
interface userDao{
List<User> findAll();
}
然后加载的是userDao.class文件,我们就可以使用当中定义的方法findAll;但是我们只定义了方法名,具体的方法实现在哪里呢?具体实现的地方就是在之前提到的mapper中
也就是说,一个表中的元素对应一个类,一个表的操作名称对应一个接口,一个表的具体操作方法对应的是一个mapper文件
现在我们就很明确了,接下来要知道的就是如何将这三个文件以及数据库中的表给关联起来。。
Mybatis声明类的属性名称要与数据库中表的列名称相同,这样就实现了表到类的映射,两者关联起来了
Mybatis声明mapper文件中的方法的id与接口中的方法名称相同,这样方法名与方法的具体实现也关联起来了
接口中的方法操作的是表,这样类与接口之间也实现了关联
这样Mybatis的基础我们就很明确了
1、读取配置
2、建造工厂
3、打开事务session
4、事务与具体的mapper文件关联
5、事务调用接口中的方法
根据SqlMapperConfig.xml找到mapper资源的位置
根据位置找到对应的具体mapper(也就是一个表对应的xml文件)
读取***.class文件中的配置得到方法名
根据方法名获取mapper文件中的同名id的标签
执行该标签体
6、事务提交
7、各种流关闭
这样Mybatis的基础就OK了
其他关于Mybatis要学习的就是多表查询,具体的sql语句该怎么配置,Mybatis缓存,取别名操作等等
使用步骤:
1、创建对应的Dao接口,例如:com.Dao.UserDao
2、创建相应的资源文件,例如:SqlMapperConfig.xml
配置该文件:(要求该文件的全类型名与UserDao文件的全类型名相同)
<?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>
<environments default="mysql"><!--默认的环境-->
<environment id="mysql"><!--创意一个环境-->
<!--类型为JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源为连接池-->
<dataSource type="POOLED">
<!--连接池的属性-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/userdb?characterEncoding=utf-8&amp&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="qaz987123"/>
</dataSource>
</environment>
</environments>
<!--映射文件的位置-->
<mappers><!--要求是-->
<mapper resource="com/domain/Dao/UserDao.xml"></mapper>
<!--取别名操作,将上面这句话换做
<package name="com.Dao"/>
这句话就是说该路径下所有的接口都可以直接写接口名称,不用写具体的路径使用
比如在后面要用到的
<select id="findAll" resultType="com.domain.User">...</select>
可以写作
<select id="findAll" resuleType="User">
-->
</mappers>
</configuration>
3、创建相应的资源配置文件,例如:resources/com.Dao.UserDao.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="com.domain.Dao.UserDao"><!--namespace要求是对应的Dao接口 文件的空间-->
<!--配置sql语句-->
</mapper>
4、在UserDao中配置相应的函数,并且关联到对应的mapper中去
例如在UserDao中写:
void insertUser(User user);//在数据库中插入user对象
List<User> findAll();
void saveUser(User user);
void updateUser(User user);
void deleteUser(User user);
User findUserById(Integer id);
List<User> findByName(String name);
int findTotal();
则在UseeDao.xml中的mapper配置
<!--id与函数名称相同,parameterType表示接收到的数据类型-->
<insert id="saveUser" parameterType="com.domain.User">
insert into user values (null ,#{name}, #{gender}, #{age}, #{address}, #{qq}, #{email});
</insert>
<!--id与函数名称相同,resultType表示将返回值封装成的类型-->
<!--因此要求JavaBean中的数据类型与数据库中表的字段名相同-->
<select id="findAll" resultType="com.domain.User">
select * from user;
</select>
<insert id="saveUser" parameterType="com.domain.User">
insert into user values (null ,#{name}, #{gender}, #{age}, #{address}, #{qq}, #{email});
</insert>
<update id="updateUser" parameterType="com.domain.User">
update user set name = #{name}, address = #{address}, gender = #{gender}, qq=#{qq}, email=#{email}, age=#{age} where id=#{id};
</update>
<delete id="deleteUser" parameterType="com.domain.User">
delete from user where id = #{id};
</delete>
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.domain.User">
select * from user where id = #{id};
</select>
<select id="findByName" resultType="com.domain.User" parameterType="String">
<!--模糊查询-->
select * from user where name like #{name}
<!--另一种方式:
select * from user where name like '%${value}%'
在这种写法中,虽然接收到的也是任意字符串,应该与上面的语句一样,花括号中的key值可以随意取,但是因为Mybatis将值封装在了value中,因此只能用value>
</select>
<select id="findTotal" parameterType="com.domain.User" resultType="Integer">
select count(id) from user;
</select>
5、使用Mybatis进行增删改查:
private InputStream in = null;
private SqlSessionFactoryBuilder builder = null;
private SqlSessionFactory factory = null;
private SqlSession session = null;
private UserDao mapper = null;
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");//动态读取并且解析资源文件
//获取SQLSessionFactory对象,采用构建者模式先创建一个FactroyBuilder
builder = new SqlSessionFactoryBuilder();
//使用builder创造一个工厂
factory = builder.build(in);
//利用工厂生产一个session对象
session = factory.openSession();
//获取dao的代理对象
mapper = session.getMapper(UserDao.class);
}
@After
public void destroy() throws IOException {
session.commit();//事务提交
session.close();//关闭各种流
in.close();
}
@Test
public void test01() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SQLSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//获取session对象
SqlSession session = factory.openSession();
//获取dao的代理对象
UserDao mapper = session.getMapper(UserDao.class);
List<User> list = mapper.findAll();
for (User user : list){
System.out.println(user);
}
session.close();
in.close();
}
@Test
public void test02() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao.class);
User user = new User();
user.setGender("女");
user.setAge(20);
user.setAddress("南阳市");
user.setName("昭君");
user.setEmail("2416345@qq.com");
user.setQq("123123123");
userDao.saveUser(user);
}
@Test
public void test_update() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao.class);
User user = new User();
user.setGender("女");
user.setAge(20);
user.setAddress("南阳市");
user.setName("茶叶");
user.setEmail("2416345@qq.com");
user.setQq("123123123");
user.setId(8);
userDao.updateUser(user);
}
@Test
public void test_delete() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao.class);
User user = new User();
user.setGender("女");
user.setAge(20);
user.setAddress("南阳市");
user.setName("茶叶");
user.setEmail("2416345@qq.com");
user.setQq("123123123");
user.setId(8);
userDao.deleteUser(user);
}
@Test
public void test_find() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao.class);
User user = userDao.findUserById(5);
System.out.println(user);
}
@Test
public void test_findByName() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao.class);
List<User> users = userDao.findByName("%王%");
for(User user : users){
System.out.println(user);
}
}
@Test
public void test_findTotal() throws IOException {
//获取dao的代理对象
UserDao userDao = session.getMapper(UserDao);
int total = userDao.findTotal();
System.out.println(total);
}
tip:
resultMap的用法
resultMap是替代resultType使用的,都是用来表示select查询到的结果封装成的数据类型的
区别在于,resultType只能表示定义好的类型,比如User,如果我使用的是条件查询,或者只查询表中的某几列该怎么办呢?
一种方法就是依然使用resultType但是返回的数据封装后就为空,但是对于多表查询的时候依然不可
另一种方法就是使用resultMap,将select查询到的结果封装为一个map就好
举例:
<mapper namespace="com.Dao.UserDao">
<!--定义user的resultMap,type表示的是返回值的类型-->
<resultMap id="UserResultMap" type="User">
<!--主键-->
<id property="id" column="id"></id>
<!--其它属性-->
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</resultMap>
<!--这里使用resultMap的话就会将返回值封装为自己定义的map-->
<select id="findAll" resultMap="UserResultMap">
select u.*, r.id as rid, r.role_name, r.role_desc from user u right outer join user_role ur on u.id = ur.uid left outer join role r on r.id = ur.rid;
</select>
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.domain.User">
select * from user where id = #{id};
</select>
</mapper>
Mybatis其他操作:
动态SQL
表示在不同情况下调用不同的查询语句
比如select * from user where username = "1"
select * from user where username = "2"
两个语句是一样的,但是条件不一样,让代码自动根据不同的条件执行不同的语句就是动态SQL
我们只需要将<select>标签中的sql体修改就好
如何修改呢?
使用<where>就好
举例:
<select id="findUsersByCondition" resultMap="userMap" parameterType="User">
select * from user
<where>
<if test="name != null">
and name = #{name}<!--表示姓名为空时将and name = #{name}补充在where语句后面-->
</if>
</where>
</select>
可以写多个<if></if>表示不同的条件
多表操作
一对多查询实质就是表间关系
体现在类中就是不同类之间的相互调用
比如User与roleAccount类两个类之间都有对方的对象
比如:
package com.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private String sex;
private String address;
private Date birthday;
private List<Role> roles;//表示的是Role的返回列表
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", birthday=" + birthday +
'}';
}
}
接下来就是说如何在配置文件中将两个表间的关系给关联起来
比如说我要查询user,条件是user中的某个属性与role中的属性有关系
我就需要在配置user的mapper的时候将role也写进去,方法就是使用collection标签
举例配置:
<mapper namespace="com.Dao.UserDao">
<!--定义user的resultMap-->
<resultMap id="UserResultMap" type="User">
<!--主键-->
<id property="id" column="id"></id>
<!--其它属性-->
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--配置另外一个表,因为上面定义的返回值是一个列表,所以使用collection-->
<collection property="roles" ofType="role">
<id column="rid" property="roleId"></id>
<result property="roleName" column="roleName_"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="UserResultMap">
select u.*, r.id as rid, r.role_name, r.role_desc from user u right outer join user_role ur on u.id = ur.uid left outer join role r on r.id = ur.rid;
</select>
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.domain.User">
select * from user where id = #{id};
</select>
</mapper>
如果定义的返回值不是一个列表(将上面定义的List<Role>替换为 Role role)
<resultMap id="UserResultMap" type="User">
<!--主键-->
<id property="id" column="id"></id>
<!--其它属性-->
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<select id="findAll" resultMap="UserResultMap">
select u.*, r.id as rid, r.role_name, r.role_desc from user u right outer join user_role ur on u.id = ur.uid left outer join role r on r.id = ur.rid;
</select>
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.domain.User">
select * from user where id = #{id};
</select>
</mapper>
关于Mybatis其他的内容,改日再写,敲键盘太累了了