mybatis是ORM(对象映射关系)的一种实现,简化了dao层(持久层)操作的一个框架,它里面封装了大量的JDBC操作。使用户更方便的操作数据库。
什么是ORM?
ORM中文翻译过来就是对象映射关系,从字面上理解就是映射我们的pojo(Planin Old Java Object)普通的java对象。它是将关系数据库和我们的pojo相互匹配的一种技术,它可以将pojo映射到数据库中,把程序中的对象持久化到关系数据库中。
什么是mybatis?
它是持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 它可以使使用xml或者注解的方式来配置或者映射原生信息
使用mybatis,这里在maven环境下搭建,并且用不同的方式开发
在pom文件中导入mybatis,和需要操作的数据库依赖
<!--导入mybatis的依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--导入mysql的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
在resource文件夹中书写mybatis的核心配置文件(mybatis-config.xml),包括配置数据库基本连接的文件(jdbc.properties)
<!-- 配置连接数据库的四个基本属性-->
driver = com.mysql.jdbc.Driver
url = jdbc:mysql:///mybatis
username = root
password =123
<!-- 配置mybatis-->
<!-- 使用resource属性引入jdbc.properties文件,获取配置连接数据库时所需的驱动、用户名、密码、url的文件 -->
<properties resource="jdbc.properties"/>
<!-- 配置mybatis默认的连接数据库的环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- 配置书写sql的文件,扫描到当前xml -->
<mappers>
<mapper resource="userMapper.xml"/>
</mappers>
这里举一个将数据插入数据库的例子,首先书写dao层代码
//dao层代码
public class UserMapper {
//定义SqlSession
private SqlSession sqlSession;
//书写构造方法,将外界的SqlSession传递进来
public UserMapper(SqlSession sqlSession){
this.sqlSession=sqlSession;
}
//书写添加方法
public void addUser(UserBean user){
//这里的两个参数一个是userMapper.xml文件中namespace和insert的ID,一个是需要插入的对象
sqlSession.insert("UserMapper.addUser",user);
}
}
编写userMapper.xml文件,在mybatis中的占位符有两种书写方式,一种为#{},另一种为${},前者可以放置sql注入,后者可以拼接sql
//编写userMapper.xml文件
<mapper namespace="UserMapper">
<insert id="addUser" parameterType="com.neuedu.domain.UserBean">
insert into
tb_user
values (
null,
#{user_name},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
#{created},
#{updated}
)
</insert>
</mapper>
//测试代码
public void test1() throws IOException {
//加载mybatis的核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建mybatis的核心对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//mybatis默认是不提交的,需要手动设置为自动提交
SqlSession sqlSession = factory.openSession(true);
UserMapper mapper = new UserMapper(sqlSession);
UserBean user = new UserBean();
user.setAge(20);
user.setBirthday(new Date());
user.setName("刘玉");
user.setPassword("abc");
user.setUser_name("ly");
mapper.addUser(user);
}
上边这种操作,需要在dao层书写繁琐的代码,使开发效率变低,mybatis给出了动态代理方法来操作dao层,使用动态代理,只需要在dao层接口中书写抽象方法,mybatis框架自己会自动的去生成实现类,进而对数据库进行操作
mapper文件的编写整体上与上边没有太大的区别,只是因为使用使用了动态代理,则在mapper文件的namespace属性中就需要书写接口的所在的包名了
//dao层接口
public interface UserMapper2 {
//书写插入数据方法
public void addUser(UserBean user );
}
<!--这里的namespace必须书写dao层接口的所在的包名-->
<mapper namespace="com.neuedu.mapper.UserMapper2">
<insert id="addUser" parameterType="com.neuedu.domain.UserBean">
insert into
tb_user
values (
null,
#{user_name},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
#{created},
#{updated}
)
</insert>
public void test2() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession(true);
UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);
UserBean user = new UserBean();
user.setAge(20);
user.setBirthday(new Date());
user.setName("小猪猪");
user.setPassword("abc");
user.setUser_name("xzz");
mapper.addUser(user);
}
mybatis可以将一些公用的sql抽取出来在mapper文件中使用sql标签对其封装,然后可以引入这些sql片段
<!-- 使用sql标签对需要封装的sql片段进行封装,
这里的ID就是当前这个sql片段的ID,
后续会通过这个ID来引用这段sql-->
<sql id="commonSQl">
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
</sql>
<!-- 引入上面定义的sql片段 -->
<select id="queryUser2" parameterType="int" resultType="user">
<!-- 使用include中的refid属性来引入上面的sql -->
SELECT <include refid="commonSQl" />
FROM kx_user
WHERE id = #{id}
</select>
mybatis的强大的地方之一就是它可以写动态sql,例如前端传来两个数据需要根据这两个数据进行模糊查询,那么就得判断这两个数据是不是都有,还是只有其中一个数据,根据不同的情况我们的sql语句也就不一样,在没使用mybatis的时候,就得进行sql的拼接,这种拼接十分的繁琐。而mybatis完美了解决了这种情况,我们可以在sql片段中加入if、where、foreach等标签从而动态的改变sql
在mapper文件中使用if标签书写动态的sql语句,假设现在有需求查询年龄小于25岁的所有用户,如果输入了用户的姓氏,那么就进行姓氏的模糊查询
<!--mapper文件的编写-->
<select id="selectUser" resultType="com.neuedu.pojo.UserBean">
select * from tb_user where age < #{age}
<!--这里使用if判断name的值是否为空,如果有多个条件同理书写多个if-->
<if test="name != null">
and name like #{name}
</if>
</select>
//演示动态sql的if条件,接口中抽象方法的书写
public User selectUser(@Param("age")Integer age , @Param("name")String name);
上面代码中,如果一个方法需要接收多个参数的话,需要使用@Parma注解对参数进行声明 使用foreach和where拼接sql,假设需求,查询ID为1,3,5,7的用户,并且如果给定了用户性别,就要加上性别查询,如果给定了用户姓氏,就需要根据姓氏进行模糊查询
//dao层接口中方法的书写
public List<User> findUser(@Param("ids") List<Integer>ids, @param("sex")Integer sex,@param("name")String name);
//mapper文件中sql的书写
<select id="selectUser" resultType="com.neuedu.pojo.UserBean">
select * from tb_user
<where>
<if test="ids != null">
id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</if>
<if test="sex != null">
and sex = #{sex}
</if>
<if test="name != null">
and name like #{name}
</if>
</where>
</select>
mybatis操作一对一,一对多,多对多查询,这里采用注解的方式
使用注解开发,就没有mapper文件了,就需要对mybatis的核心配置文件进行修改了
<mappers>
<!-- 这里必须采用包的方式配置,因为没有mapper文件,书写接口所在的包-->
<package name="com.neuedu.mapper"/>
</mappers>
public interface UserMapper3 {
@Insert("INSERT INTO tb_user
VALUES (NULL,
#{user_name},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
#{created},
#{updated}
)")
public void addUser(UserBean user);
}
public void test2() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession(true);
UserMapper3 mapper = sqlSession.getMapper(UserMapper3.class);
UserBean user = new UserBean();
user.setAge(20);
user.setBirthday(new Date());
user.setName("大魔王");
user.setPassword("abc");
user.setUser_name("mw");
mapper.addUser(user);
}
注解一对一查询,一对一查询在数据库中通常是采用引入另一个表的主键作为 外键,在Java代码中有两种思想可以进行这种一对一查询,这里采用的是在一个类中引入另一个类作为成员变量,将查询的另一个表的数据封装到当前类中的成员变量中。假设现在有一个订单表和用户表,那么站在订单表看用户表,就是一个一对一查询,在订单表的实体对象中引入用户表的实体对象作为成员变量。 pojo层订单是对象的代码书写
public class Order implements Serializable {
// 需要添加用户的引用,订单到用户是一对一
private UserBean user;
public interface IOrderMapper {
/*
一对一注解
*/
@Select("select * from tb_order where id = #{id}")
@Results(
id = "orderAndUser",
value = {
//这里的Result注解表明在tb_order表中id是主键,并且可以通过column和property来解决属性名和表中列名不对应的情况
@Result(id=true , column = "id" , property = "id"),
//这里的Result注解中column是配置表中外键中的列名,property是配置user实体类在Order实体类中的的属性名。
//one注解中配置的select,sql语句是用来查询当前订单的用户的,fetchType属性配置的是子查询是懒查询,立刻查询,延时查询,这里配置默认(DEFAULT)即可
@Result(one = @One(select="com.neuedu.mapper.IUserMapper.findUserById",fetchType = FetchType.DEFAULT ) , column = "user_id" , property = "user")
}
)
public Order findOrderAndUser(Integer id);
}
注解一对多查询,假设现在有订单表和订单明细表,一个订单对应着多个订单明细,它们之间的关系就是一对多 一对多,pojo层演示
public class Order implements Serializable {
// 一对多,在一的类中引用多,但是必须使用集合方式
private List<OrderDetail> orderDetails;
}
//首先书写主查询
public interface IOrderMapper {
@Select("select * from tb_order where id = #{id}")
@Results(
value = {
@Result(property = "id",column = "id",id = true),
@Result(property = "orderDetails",column = "id",
many = @Many(select = "com.neuedu.mapper.IOrderDetails.findOrdredetails",fetchType = FetchType.DEFAULT)
)
}
)
public Order findOrdreDetails(Integer id);
}
上边的订单表中关联着订单明细表,订单明细表关联着商品表,那么订单表和商品表就是一个多对多关系,订单明细表这个时候就作为中间表,来完成多对多查新。