欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【整理】MyBatis

程序员文章站 2022-04-13 20:51:17
...

【整理】MyBatis

此处只讲重点的内容,详细讲解请到此

Day_01:入门

1、快速入门

1)执行步骤

  • ①添加MyBatis的坐标

  • ②创建user数据表

  • ③编写User实体类

  • ④编写映射文件UserMapper.xml 【用于配置SQL语句】

  • ⑤编写核心文件SqlMapConfig.xml 【配置Mybatis核心配置】

  • ⑥编写测试类

④编写映射文件UserMapper.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">

内容:
【整理】MyBatis

<mapper namespace="userMapper">	//命名空间(这里不使用框架生成的代理对象,所以这个是自定义的)
    <!---->
    <update id="update" parameterType="com.itheima.domain.User">	//parameterType:你要传入参数的全限定名。(可以使用自定义别名或Spring提供的别名代替)
        update user set username = #{username},password =#{password} where id = #{id}	//#{xxx}:是传入参数的属性(Mybatis根据属性名称自动映射),要和数据库顺序一样。
    </update>

⑤编写核心文件SqlMapConfig.xml

约束头:

<?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">

内容:

<!--2、数据库环境-->
<configuration>    
	<environments default="development">      	  		【配置默认使用的环境是xxx】 
		<environment id="development">           	 	【给这个环境取个名:development】
			<transactionManager type="JDBC"/>     		【使用JDBC的事务管理器(transactionManage)】  
			<!--配置数据源数据-->     
			<dataSource type="POOLED">      【数据源类型:池子(池子化类型)】          
				<property name="driver" value="com.mysql.jdbc.Driver"/>		【name是属性(属性固定)】
				<property name="url" value="jdbc:mysql:///test"/>                
				<property name="username" value="root"/>
				<property name="password" value="root"/>            
			</dataSource>        
		</environment>    
	</environments>    
	
    <!--3、加载映射文件-->
	<mappers> 
		<mapper resource="com/itheima/mapper/UserMapper.xml"/> 		
	</mappers>
</configuration>

关于加载映射文件的另一种方式:
扫mapper配置文件的包名,加载所有配置文件,不用一个一个的添加了:

<mapper>
	<package name ="com.itheima.mapper"/>
</mapper>

映射文件一定要加载映射关系,不然SQL没有功能。

⑥编写测试类

@Test
    public void Demo04() throws IOException {
        //模拟:封装好数据的实体类
        User user = new User();
        user.setId(6);
        user.setUsername("张学友");
        user.setPassword("abc");
            //加载核心配置文件
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            //获取SqlSessionFactory对象
            SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //获取sqlSession会话对象
            SqlSession sqlSession = SqlSessionFactory.openSession();
        //执行SQL
        sqlSession.insert("userMapper.update",user);//命名空间.id
        //提交事务
        sqlSession.commit();//Mybatis默认不提交事务
            //释放资源
            sqlSession.close();
    }

2)Mybatis核心配置文件:概述

【整理】MyBatis

①environments标签

【整理】MyBatis
【整理】MyBatis

②mapper标签

【整理】MyBatis

③Properties

在核心配置文件上配置
【整理】MyBatis

 <!--加载jdbc配置文件-->
    <properties resource="jdbc.properties"/>
    <!--数据源环境-->
    <environments default="develoment">
        <environment id="develoment">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

④typeAliaser

我们会发现如果每次配置SQL语句指定参数类型的时候,都要填写全类名,这样太繁琐了。
我们可以配置typeAliaser标签,指定某个类是某个别名来进进行代替。

【整理】MyBatis
Mybatis提供的别名我们不需要自行配置,但是,自定义的类需要自己必须要配置。
【整理】MyBatis

核心配置文件:

<configuration>
    <!--加载jdbc配置文件-->
    <properties resource="jdbc.properties"/>
    【注意标签顺序】
    
 <!--自定义别名-->
    <!--方式1:指定具体某个类-->
    <typeAliases>
        <typeAlias type="com.itheima.domain.User" alias="user"/>
    </typeAliases>
        
	<typeAliases>
        <!--方式2:扫包-->
        <package name="com.itheima.domain"/>
    </typeAliases>
`

映射文件:

	<!---->
    <delete id="delete" parameterType="int">
        delete from user where id = #{id}   <!--因为唯一,名称随意-->
    </delete>
    <!---->
    <update id="update" parameterType="user">
        update user set username = #{username},password =#{password} where id = #{id}
    </update>

注意:配置typeAliases一定要注意配置标签之间的顺序(其他也要遵守)
【整理】MyBatis

3)MyBatis相关API

①SqlSessionFactoryBuilder工厂构建对象

【整理】MyBatis

②SqlSessionFactory工厂对象

工厂对象专门制造对象的。
【整理】MyBatis

③SqlSession会话对象(重要)

【整理】MyBatis

Day_02:

一、Dao层实现原理

1)代理开发方式

以前我们使用dao层,自己要写dao接口和dao实现类,但是Mybatis可以只有接口(类似dao),没有实现;实现实际上是动态代理对象,框架帮我生成
【整理】MyBatis
这个”全限定名还没改↓”
(xml配置的namespace = 接口的全限定名)
【整理】MyBatis
【整理】MyBatis

代码实现:

①配置Mapper
<mapper namespace="com.itheima.dao.UserMapper">	//接口全限定名

<!--查询所有User(无参)-->
    <select id="findAll" resultType="user">
        select * from USER
    </select>
<!--根据id查询User(参数int id)-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>
</mapper>
②定义接口
public interface UserMapper {

    public List<User> findAll() throws IOException;

    public User findById(int id);
}
③测试代码
public class Demo01 {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
        
        //执行SQL
        List<User> userList = mapper.findAll();
        //执行SQL、
        User user = mapper.findById(1);

        System.out.println(userList);System.out.println(user);
        //释放资源
        sqlSession.close();
    }
}

【整理】MyBatis

2)Mybatis映射文件深入:动态SQL

【整理】MyBatis

1)if(重要)

业务场景:用于筛选条件操作数据库,条件不确定

可能1个,可能多个,可能没有
select * from user
select * from user where id=?
select * from user where id=? and username=?
select * from user where id=? and username =? and password=?

Mapper配置文件

<mapper namespace="com.itheima.dao.UserMapper">
    
    <select id="findByConditon" resultType="user" parameterType="user">

        select * from USER
        
        <where>
            <if test="id!=0">
                and id = #{id}
            </if>
            <if test="username!=null">	//属性名称
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
        </where>
        
    </select>

<where>附加条件</where>
如果附加条件不满足就不进行SQL语句拼接,如果全部满足<where>标签以及标签内等于没有

2)foreach

业务场景:循环执行sql的拼接操作

select * from user where id = 1 or id = 2 ,id =3在1-3之内查询: 有什么就查什么,没有就不查询:
等于
select * from user id in(1,2,3)

因此在( )之内,也是动态的,不确定的。

Mapper配置文件

<mapper namespace="com.itheima.dao.UserMapper">

    <select id="findByIds" parameterType="list" resultType="user">

        select * from user  <!--where id in (1,2,3)-->

        <where>
            <foreach collection="list" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>

解析:

  • parameterType=“list”:list是框架定义好的别名
  • collection:翻译“集合”,这里填你传入参数的类型,(可以填集合,也可以填数组(数组填“arrays”))
  • open:从哪里开始
  • close:从哪里结束
  • item:翻译“项”,意思是从collection中取出的每一项的值
  • separator:分隔符

select * from user where id in(1,2,3) = select * from user where “open + item + separator + close”

3)抽取重复的sql

抽取:<sql id=“selectUser”>select * from user</sql>
引入:<include refid=“selectUser”></include>

Mapp配置文件
【整理】MyBatis

二、Mybatis核心配置文件深入

1)typeHandlers标签

类型转换器,java数据类型数据库的数据类型,或者 数据库数据类型java数据类型
如果要特将某个java类型能够转数据库数据类型就要自定义,下面是预处理器帮我们转换的。
【整理】MyBatis
【整理】MyBatis
下面使用代码的形式解析:

目的:将java的Date类型 存进 数据库bigint数据类型中;操作数据库时,将返回bigint类型的数据 又转回成 Date类型,返回给java
解决:定义一个类型转换器:将Date类型数据转换成毫秒值的类型存进数据库中;数据库返回时,又将 毫秒值Date


数据库:

【整理】MyBatis

自定义转换器:继承BaseType<T>

③复写4个方法

详解执行SQL对象

public class DateTpyeHandler extends BaseTypeHandler<Date> {//<T>:T为你要转换的数据类型
    //将java类型 转换成 数据库字段的数据类型
    @Override                                                          //int i:为Date参数的位置(执行SQL中传入的参数位置)
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        //将Date转换成毫秒值
        long time = date.getTime();
        //设置参数,设置要转换的毫秒值
        preparedStatement.setLong(i,time);
    }
    
    //将数据库字段数据类型 转换成 java类型
    //String:需要转换数据类型的字段名称
    //ResultSet:数据库查询出来的结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        //获取结果集中需要转换的数据类型(long)
        long aLong = resultSet.getLong(s);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
    
    //将数据库字段数据类型 转换成 java类型
    //int i:需要转换数据类型的字段位置
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        //获取结果集中需要转换的数据类型(long)
        long aLong = resultSet.getLong(i);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
    
    //将数据库字段数据类型 转换成 java类型
    //int i:需要转换数据类型的字段位置
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        //从CallableStatement中获取需要转换的数据类型(long)
        long aLong = callableStatement.getLong(i);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
}

④MyBatis中注册转换器

注意配置与配置之间的 配置顺序

 <!--注册类型转换器-->
    <typeHandlers>
        <typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
    </typeHandlers>

⑤测试

Mapper配置:

<mapper namespace="com.itheima.dao.UserMapper">

    <sql id="selectUser">select * from user</sql>
    
    <!--插入数据:测试java类型转数据库类型数据-->
    <insert id="save" parameterType="user">
        insert into user values (#{id},#{username},#{password},#{birthday})
    </insert>
    
    <!--查询数据:测试数据库转java类型数据-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>

测试类:

//数据库转java类型数据
    @org.junit.Test
    public void Demo03() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //执行SQL
        User user = mapper.findById(10);
        System.out.println(user);
        sqlSession.close();

    }
//java转数据库类型数据
    @org.junit.Test
    public void Demo04() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //模拟封装好请求参数的user
        User user = new User();
        user.setUsername("刘德华");
        user.setPassword("123");
        user.setBirthday(new Date());
        //执行SQL
        mapper.save(user);
        System.out.println(user);
        sqlSession.close();

    }

2)plugins标签

plugins(插件)可以导入插件拓展Mybatis功能,下面 演示分页插件的功能
【整理】MyBatis

①pom.xml:导入分页插件

 <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>

②Mybatis核心配置文件:配置分页插件

    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>    <!--指定方言:(指定什么数据库)因为不同数据库sql命令可能不一样-->
        </plugin>
    </plugins>

③测试

    @org.junit.Test
    public void Demo05() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
        
        //设置分页相关参数      参数(当前页码,每页显示条数)
        PageHelper.startPage(1,3);//显示第1页的3条数据
        //执行SQL
        List<User> users = mapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

分页插件:获取其他相关参数

    @org.junit.Test
    public void Demo05() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //设置分页相关参数      参数(当前页码,每页显示条数)
        PageHelper.startPage(2,3);//显示第1页的3条数据
        //执行SQL
        List<User> users = mapper.findAll();//查询所有user
        for (User user : users) {
            System.out.println(user);
        }
        //获取分页相关的参数
        PageInfo<User> info = new PageInfo<User>(users);//<T>:你要进行分页的Bean对象    参数:返回查询user的集合
        System.out.println("当前页码:"+info.getPageNum());
        System.out.println("每页显示条数:"+info.getPageNum());
        System.out.println("总条数:"+info.getTotal());
        System.out.println("总页码:"+info.getPages());
        System.out.println("上一页:"+info.getLastPage());
        System.out.println("下一页:"+info.getNextPage());
        System.out.println("第一页:"+info.getFirstPage());
        System.out.println("最后一个:"+info.getLastPage());
        System.out.println("是否为第一页:"+info.isIsFirstPage());
        System.out.println("是否为最一页:"+info.isIsLastPage());
        //....
        sqlSession.close();//释放资源
    }

知识小结

【整理】MyBatis

Day_03:多表查询

此处为了简洁,将省去测试类,只放重点。如果想详细,请点击此处

环境搭建:

数据库

【整理】MyBatis

sqlMapCongfig.xml

<?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>
    <!--加载jdbc配置文件-->
<properties resource="jdbc.properties"/>
    <!--自定义别名-->
    <typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user" />
<typeAlias type="com.itheima.domain.Order" alias="order" />
    </typeAliases>

    <!--注册类型转换器-->
    <typeHandlers>
        <typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
    </typeHandlers>
    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>    <!--指定方言:(指定书目数据库)因为不同数据库sql命令可能不一样-->
        </plugin>
    </plugins>
<!--搭建数据源环境-->
<environments default="develoment">
    <environment id="develoment">
        <transactionManager type="JDBC"></transactionManager>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/itheima/mapper/UserMapper.xml"/>
        <mapper resource="com/itheima/mapper/OrderMapper.xml"/>
    </mappers>


</configuration>

关于自定义别名:

【还有1中自定义别名的方式是:扫包】

<!--自定义别名-->
    <typeAliases>
<package name = "com.iiheima.domain"/>

【扫实体类的包,它会将包下的所有实体类都定义别名,别名为该实体类名称的首字母小写。】

实体类:User&Order(订单)

public class User {
    private int id;
    private String username;
    private String password;
    //忽略get、set方法和toString
    
}


public class Order {
    private int id;
    private Date orderTime;//下单时间
    private double total;//订单价格
    private User user; //当前订单属于哪个客户
	//忽略get、set方法和toString

一、XML配置方式:

1)一对一

【整理】MyBatis
问题: 单单查询Order表是不能够查询出来User的,因为Order表中没有User类型的字段,只有1个相关的uid。

【整理】MyBatis
铺垫:
先让order表和user表结合成1个表:内连接查询

SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.id

【整理】MyBatis

解决:

手动指定:字段名与实体类属性的映射关系
(将查询结果集的字段 映射到 实体类的属性中)

①OrderMapper接口

public interface OrderMapper {
    List<Order> findAll();
}

②OrderMapper.xml


<mapper namespace="com.itheima.mapper.OrderMapper">
    <!--
    【手动指定:字段名与实体类属性的映射关系	(将查询结果集的字段映射到实体类的属性中)】
        type:你要封进的实体类
        column:数据库字段名称  (id:表示 主键   result:表示 普通字段 【都是返回查询结果的字段】)
        property:实体类属性
    -->
    <resultMap id="orderMap" type="order">   <!--order自定义别名(全限定名)-->
		//Order的简单属性
        <id column="oid" property="id"/>    <!--数据库的oid 对应着 实体类属性的id-->
        <result column="orderTime" property="orderTime"/>
        <result column="total" property="total"/>

        <result column="uid" property="user.id"/>
        <result column="username" property="user.username"/>
        <result column="password" property="user.password"/>
        <result column="birthday" property="user.birthday"/>
    </resultMap>

    <select id="findAll" resultMap="orderMap">			<!--resultMa:指定哪个结果映射的id标识-->
        SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.uid
    </select>

</mapper>

映射过程

【整理】MyBatis

映射原理

【整理】MyBatis

Mapper的第二种配置:

OrderMapper.xml:

<resultMap id="orderMap" type="order">   <!--自定义别名-->
	//Order的简单属性
    <id column="oid" property="id"/>    <!--数据库的oid 对应着 实体类属性的id-->
    <result column="orderTime" property="orderTime"/>
    <result column="total" property="total"/>
	//Order的User集合属性
    <!--
    association :翻译“匹配”
    property:表示实体类(order)的属性名称(private User user)
    javaType:表示实体类属性的类型(User)(全限定名)
    column:数据库返回结果集的字段名称
    property:实体类属性名称
    -->
    
    <association property="user" javaType="user">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
    </association>
</resultMap>

2)一对多

【整理】MyBatis

①User属性

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    
    //当前用户有哪些订单
    private List<Order> orderList;

②UserMapper接口

public interface UserMapper {
    List<User> findAll();
}

问题:

  • 1)单单查询User表显示不了order表的信息,但发现order关联user的id。
  • 2)mapper怎么手动指定;List集合属性的映射关系

解决:

铺垫:
先让order表和user表结合成1个表:内连接查询

SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.id

【整理】MyBatis

③UserMapper.xml

<mapper namespace="com.itheima.mapper.UserMapper">
        <resultMap id="userMap" type="user">
        		//User的简单属性
                <id column="id" property="id"/>
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                <result column="birthday" property="birthday"/>
        		//User的Order集合属性
         <!--配置集合:
                  property:User中集合的属性名称(List<Order> orderList)
                  ofType:集合的类型(Order)(全限定名:此处使用了自定义别名)
                  column:字段名称

                -->
                <collection property="orderList" ofType="order">
                        <!--封装Order数据-->
                        <id column="oid" property="id"/>
                        <result column="ordertime" property="orderTime"/>
                        <result column="total" property="total"/>
                </collection>
                
        </resultMap>
        
        <select id="findAll" resultMap="userMap">
                select * ,o.id oid from user u ,orders o where u.id=o.uid
        </select>
        
</mapper>

3)多对多

【整理】MyBatis
(将3个表进行内连接查询)

数据库:

【整理】MyBatis

select * from sys_user u,sys_user_role ur ,sys_role r where u.id = ur.userId and r.id = ur.roleId

【整理】MyBatis

①增加role实体类

public class Role {
    private int id;
    private String roleName;
    private String roleDesc;
    //省略set/get方法
}

②增加user实体类成员变量

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    private List<Order> orderList;//当前用户有哪些订单
    
    //当前用户具备哪些角色
    private List<Role> roleList;

③UserMapper接口

public interface UserMapper {
    List<User> findUserAndRoleAll();
}

④UserMapper.xml

<mapper namespace="com.itheima.mapper.UserMapper">
<resultMap id="userRoleMap" type="user">        <!--type:封进哪里的全限定名-->
                <!--User的简单属性-->
                <id column="userId" property="id"/>                <!--column:结果集字段-->
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                <!--User的roleList的Role集合属性-->
                <collection property="roleList" ofType="role">  <!--ofType:集合类型(全限定名)-->
                        <id column="roleId" property="id"/>
                        <result column="roleName" property="roleName"/>
                        <result column="roleDesc" property="roleDesc"/>
                </collection>
        </resultMap>
        <select id="findUserAndRoleAll" resultMap="userRoleMap">
            select * from sys_user u ,sys_user_role ur,sys_role r where u.id = ur.userId and r.id = ur.roleId
        </select>
</mapper>

二、注解开发方式

1)概述

【整理】MyBatis

2)简单de增删改查

①Mybatis核心文件配置

删除了mapper配置文件,接口和实体类是没有映射关系的,因为没有配置值文件Mybatis不知道谁跟谁有映射关系,不使用xml配置的话,记得要加载映射关系

【这里是扫接口的包】

    <!--加载映射关系-->
    <mappers>
        <!--指定接口所在的包(扫包)-->
         //<!--<mapper resource="com/itheima/mapper/AccountMapper.xml"></mapper>-->
        <package name="com.itheima.mapper"/>
    </mappers>

②UserMapper接口:声明注解

这里跟xml文件一样的,用方法的参数来赋SQL值

public interface UserMapper {

    @Insert("insert into user values(#{id},#{username},#{password})")
    void save(User user);

    @Update("update user set username=#{username},password=#{password} where id=#{id}")
    void  update(User user);

    @Delete("delete from user where id = #{id}")
    void  delete(int id);

    @Select("select * from user where id = #{id}")
    User findById(int id);

    @Select("select * from user")
    List<User> findAll();
}

③测试

public class Demo {
    public User user = new User();
    public UserMapper mapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(UserMapper.class);
    }
    //增
    @Test
    public void testSave(){
        user.setUsername("我是谁");
        user.setPassword("123");
        mapper.save(user);
    }
    //删
    @Test
    public void testDeleteById(){
        mapper.delete(3);
    }
    //改
    @Test
    public void testUpdateById(){
        user.setId(1);
        user.setUsername("易烊");
        user.setPassword("123");
        mapper.update(user);
    }
    //查:1个
    @Test
    public void testFindAll(){
        List<User> userList = mapper.findAll();
        System.out.println(userList);
    }
    //查:所有
    @Test
    public void testFindById(){
        User user = mapper.findById(1);
        System.out.println(user);
    }

}

3)实现复杂映射开发

1)一对一

【整理】MyBatis

0、实体类
public class User {
    private int id;
    private String username;
    private String password;
    //忽略get、set方法和toString
    
}
public class Order {
    private int id;
    private Date orderTime;//下单时间
    private double total;//订单价格
    private User user; //当前订单属于哪个客户
	//忽略get、set方法和toString
①OrderMapper接口
public interface OrderMapper {
    
    @Select("select * from user u,orders o where o.uid = u.id")
    
    @Results({
            //Order的简单属性
            @Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            //Order的User对象属性
            @Result(column = "uid",property = "user.id"),//返回结果集的字段 与 Order中User对象的属性值
            @Result(column = "username",property = "user.username"),
            @Result(column = "password",property = "user.password")
    })
    
    List<Order> findAll();
}

②测试
public class Demo2 {
    public User user = new User();
    public OrderMapper mapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(OrderMapper.class);
    }
    @Test
    public void test1(){
        List<Order> orderList = mapper.findAll();
        for (Order order : orderList) {
            System.out.println(order);
        }
    }
对比一下xml:

【整理】MyBatis

2)一对多

【整理】MyBatis

2、一对一的第2种方式(常用)

第2种是什么方式呢?

上边的方式是使用内连接将2个表合成为1个表来查询
下面是通过1个表,1个表的查询
具体是 怎么样呢?

  • 先查询orders表返回查询结果集
  • 指定查询结果集中的uid(oders表中的外键,user表的主键), 根据uid查询user表

select * from useru,orders o where o.uid = u.id
↓分开
select * from orders (OrderMapper)
↓根据uid(复用)
select * from user where id = ? (UserMapper)

代码跟前面整个注解演示相关,这里只写出有改动的。

①UserMapper接口(上边已经定义<复用>)
根据id查询User:

 @Select("select * from user where id = #{id}")
    User findById(int id);
②OrderMapper接口
public interface OrderMapper {

    @Select("select * from orders")

    @Results({
            //Order的简单属性
            @Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            //Order的User对象属性
            @Result(
                    property = "user",  //Order实体需要封装的属性名称
                    column = "uid",     //根据orders返回查询结果集中的哪个字段进行查询
                    javaType = User.class,  //Order中user属性名称的属性类型
                    //1对1
                    one = @One(select = "com.itheima.mapper.UserMapper.findById" )   //select属性:查询哪个接口的方法 获得 Order实体需要封装的属性
            )
    })//记得,这里是{ }是数组。

    List<Order> findAll();
}

3)多对多

【整理】MyBatis

多对多:多对多都是有个中间表,这里也是将3个表的内连接,拆分成2个表来查询

根据User的id 查询 某个User具备哪些角色:
select * from user u ,sys_user_role ur , sys_role r where ur.roleId = r.id and u.id = ?
↓ 拆分
select * from user
↓ 根据id查询
select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = ?
【整理】MyBatis

①Role实体类
public class Role {
    private int id;
    private String roleName;
    private String roleDesc;
②User实体类
public class User {
    private int id;
    private String username;
    private String password;
    //当前User具备多少个角色
    private List<Role> roleList;
③RoleMapper接口
public interface RoleMapper {
    @Select("select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = #{uid}")
    List<Role> findByUid(int uid);
}
④UserMapper接口
public interface UserMapper {

    @Select("select * from user")
    @Results({
            //User的简单属性
            @Result(column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
           
            //User中Role集合属性
            @Result(
                    property = "roleList",  //封进哪个属性
                    column = "id",          //根据哪个字段查询
                    javaType = List.class,  //封进哪个属性的属性类型
                    //多对多
                    many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid")    //调用某个方法查询
            )
    })
    List<User> findUserAndRoleAll();

Mybatis+MySQL:插入记录,返回数据自动生成的id

【整理】MyBatis
这里还有1个属性keyColumn没设置,但是看下面解释应该能懂

useGeneratedKeys:必须设置为true,否则无法获取到主键id。
keyProperty:设置为POJO对象的主键id属性名称。
keyColumn:设置为数据库记录的主键id字段名称

mybatis中@Param的用法和作用

```java
@Select("select s_id id,s_name name,class_id classid from student where  s_name= #{aaaa} and class_id = #{bbbb}") 
    public Student select(@Param("aaaa") String name,@Param("bbbb")int class_id);  

当方法参数时1个时, 自定义命名可以直接映射,但是如果是多参数的话,即使每个参数的名称都是跟数据库字段名称一致,但是他还是分不清,所以要使用@Param注解来声明跟字段相匹配的名称。
(如果是对象的话,对象属性名称跟数据库名称相对应就可以映射。)

相关标签: 【四】三大框架

上一篇: SpringMVC

下一篇: YD:SSM整合