MyBatis技术

MyBatis技术

Scroll Down

mybatis是ORM(对象映射关系)的一种实现,简化了dao层(持久层)操作的一个框架,它里面封装了大量的JDBC操作。使用户更方便的操作数据库。

  1. 什么是ORM?
  • ORM中文翻译过来就是对象映射关系,从字面上理解就是映射我们的pojo(Planin Old Java Object)普通的java对象。它是将关系数据库和我们的pojo相互匹配的一种技术,它可以将pojo映射到数据库中,把程序中的对象持久化到关系数据库中。
  1. 什么是mybatis?
  • 它是持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  • 它可以使使用xml或者注解的方式来配置或者映射原生信息
  1. 使用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);
    }

  1. 上边这种操作,需要在dao层书写繁琐的代码,使开发效率变低,mybatis给出了动态代理方法来操作dao层,使用动态代理,只需要在dao层接口中书写抽象方法,mybatis框架自己会自动的去生成实现类,进而对数据库进行操作
  • mapper文件的编写整体上与上边没有太大的区别,只是因为使用使用了动态代理,则在mapper文件的namespace属性中就需要书写接口的所在的包名了
//dao层接口
public interface UserMapper2 {
    //书写插入数据方法
    public void addUser(UserBean user );
}

  • mapper文件的编写
<!--这里的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);
    }

  1. mybatis可以将一些公用的sql抽取出来在mapper文件中使用sql标签对其封装,然后可以引入这些sql片段
  • mapper文件中演示
	<!-- 使用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>

  1. 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 &lt; #{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>

  1. mybatis操作一对一,一对多,多对多查询,这里采用注解的方式
  • 使用注解开发,就没有mapper文件了,就需要对mybatis的核心配置文件进行修改了
	<mappers>
        	<!-- 这里必须采用包的方式配置,因为没有mapper文件,书写接口所在的包-->
        	<package name="com.neuedu.mapper"/>
    	</mappers>

  • dao层接口书写
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;

  • dao层接口中代码的书写
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;
}
  • 一对多,dao层接口演示
//首先书写主查询
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);
}

  • 上边的订单表中关联着订单明细表,订单明细表关联着商品表,那么订单表和商品表就是一个多对多关系,订单明细表这个时候就作为中间表,来完成多对多查新。