MyBatis【从入门到基本精通】


……

一、MyBatis的基本使用

1、MyBatis作用

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

  • MyBatis可以使用简单的XML用于配置和原始映射,将接口和Java的POJO类映射成数据库中的记录

  • 使开发者只需要关注 SQL
    本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的
    过程代码。

2.MyBatis的历史

原是apache的一个开源项目iBatis,2010年6月这个项目由apache software foundation
迁移到了google code,并且改名为MyBatis 。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。

3.为什么要使用MyBatis?

JDBC的缺点

  • SQL夹在Java代码块里,耦合度高导致硬编码内伤
  • 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
  • 要自已创建connection、创建statement、手动设置参数、结果集检索等

Hibernate的缺点

  • 长难复杂SQL,对于Hibernate而言处理也不容易
  • 内部自动生产的SQL,不容易做特殊优化。

MyBatis的好处:

  • 对开发人员而言,核心sql还是需要自己优化
  • MyBatis是一个半自动化的持久化层框架。
  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

二、MyBatis的开发步骤

1、下载Mybatis核心包

http://www.mybatis.org/mybatis-3/getting-started.html

https://github.com/mybatis/mybatis-3/releases

2、创建工程,引入MyBatis核心包及依赖包

在这里插入图片描述

3、创建customer表

1 CREATE TABLE customer(
2 cust_id int PRIMARY KEY,
3 cust_name varchar(50),
4 cust_profession VARCHAR(50),
5 cust_phone VARCHAR(50),
6 cust_email VARCHAR(50)
7 )

4、建立与表对象的domain,创建Customer实体类我在IDEA中用了lombok jar包

 package com.lqg.domain;
 2 
 3 import lombok.Getter;
 4 import lombok.Setter;
 5 
 6 @Setter@Getter
 7 public class Customer {
 8 
 9     private Integer cust_id;
10     private String  cust_name;
11     private String  cust_profession;
12     private String  cust_phone;
13     private String  cust_email;
14 
15     @Override
16     public String toString() {
17         return "Customer{" +
18                 "cust_id=" + cust_id +
19                 ", cust_name='" + cust_name + '\'' +
20                 ", cust_profession='" + cust_profession + '\'' +
21                 ", cust_phone='" + cust_phone + '\'' +
22                 ", cust_email='" + cust_email + '\'' +
23                 '}';
24     }
25 }

5、创建与表对象的关系映射Mapping文件编写sql语句

<?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="Mytest">
 6     <!--根据id查询用户-->
 7     <select id="queryCustomerById" parameterType="Int" resultType="com.lqg.domain.Customer">
 8         select * from `customer` where cust_id = #{cust_id}
 9     </select>
10     
11 </mapper>

6、在核心配置文件当中引入Mapping

<!--加载映射文件-->
<mappers>
<mapper resource="com/lqg/domain/Customer.xml"></mapper>
</mappers>

7、创建工厂,执行sql语句

package com.lqg.test;

import com.lqg.domain.Customer;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {
    @Test
    public void test() throws IOException {
        //1.创建一个SqlSessionFactoryBulider的类
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.加载SqlMapConfig.xml的配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //3.创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
       //4.创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //5.用sqlSession对象执行查询
        Customer customer = sqlSession.selectOne("queryCustomerById",1);
        System.out.println(customer);
     

    }
}

8通过用户id查询结果如下:

在这里插入图片描述

三. MyBatis的入门程序:

4.1、MyBatis的CRUD操作

MyBatis查询一个,多个以及增删改

4.4.1通过用户id进行查询

对应映射配置

<select id="queryCustomerById" parameterType="Int" resultType="com.domain.Customer">
	 SELECT * FROM `customer` WHERE cust_id  = #{cust_id}
</select>

在测试类里面查询

Customer c = session.selectOne("queryCustomerById", 1);

查询所有用户
在对应的映射文件里面配置

<select id="queryAllCustomer" resultType="com.domain.Customer">
       select * from customer 
</select>

模糊查询(同查询所有差不多)

<select id="queryAllByName" parameterType="String" resultType="com.lqg.domain.Customer">
        select * from customer where cust_name like '%${value}%'
</select>

4.4.2、总结

  1. parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中

  2. resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中

  3. selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常

  4. selectList可以查询一条或多条记录

  5. #{}
    表示一个?占位符号,通过#{}可以实现preparedStatement向占位符中设置值
    自动进行java类型和jdbc类型转换,可以有效防止sql注入
    #{}可以接收简单类型值或pojo属性值
    如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称
    里面的参数传递过来都是加上’'引号的,

  6. s q l p o j o {} 表示拼接sql串,可以接收简单类型值或pojo属性值 通过 {}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
    如果parameterType传输单个简单类型值,${}括号中只能是value

5、保存更新删除

5.1添加用户

对应关系映射配置

<insert id="insertCustomer" parameterType="com.domain.Customer">
    insert into `customer` values(#{cust_id},#{cust_name},#{cust_profession},
    #{cust_phone},#{cust_email})
</insert>

注意:如果添加操作后面直接跟的表名,赋值里面的所有字段都要写上包括自动增长的id,如果是跟字段那值就跟上自己写的字段一一对应

5.5.1、添加用户的方法测试代码

SqlSession session = MyBatisUtils.openSession();
       	Customer customer = new Customer("老王","服务员","17364343463","[email protected]");
        session.insert("insertCustomer",customer);
        session.commit();

注意:当要修改数据库中的记录的时候,执行sql时候需要自己提交事务

5.5.2、返回添加过后自增的主键两种方式
方式一:获取插入最后一个id(写在insert标签里面)

<selectKey keyColumn="cust_id" keyProperty="cust_id" resultType="Integer" order="AFTER">
          				select last_insert_id()
</selectKey>

方式二:获取插入的最后一个id(这种方式比第一种简单)*

<insert id="insertCustomer" parameterType="Customer" useGeneratedKeys="true" keyProperty="cust_id" keyColumn="cust_id">	
   //keyColumn可以不写
   insert into customer(cust_name,cust_profession,cust_phone)
    values(#{cust_name},#{cust_profession},#{cust_phone});
</insert>
				

5.2更新用户

对应关系映射配置

<update id="updateCustomerById" parameterType="com.lqg.domain.Customer">
        update customer set cust_name =#{cust_name} where cust_id = #{cust_id}
</update>

5.2.1、修改用户的方法测试代码

Customer customer1 = new Customer();
        customer1.setCust_id(7);
        customer1.setCust_name("王麻子");
        customer1.setCust_profession("清洁工");
        customer1.setCust_email("78754579846");
        int row= sqlSession.insert("saveCustomer",customer1);
        int row2 = sqlSession.update("updateCustomerById",customer1);
        session.commit();

5.3删除用户

对应关系映射配置

<delete id="deleteCustomerById" parameterType="com.lqg.domain.Customer">
        delete from customer where cust_id=#{cust_id}
</delete>

5.3.1、修改用户的方法测试代码

     Customer customer1 = new Customer();
        customer1.setCust_id(7);
        customer1.setCust_name("王麻子");
        customer1.setCust_profession("清洁工");
        customer1.setCust_email("78754579846");
        int row= sqlSession.insert("saveCustomer",customer1);
        int row2 = sqlSession.update("updateCustomerById",customer1);
        sqlSession.delete("deleteCustomerById",7)
        session.commit();

四、MyBatis开发Dao

1、原始的Dao开发方法

1.1、创建CustomerDao接口类

package com.lqg.dao;

import com.lqg.domain.Customer;

import java.util.List;

public interface CustomerDao {
    public Customer findCustomerById(Long cust_id);
    public List<Customer> findAllCustomer();
    public int saveCustomer(Customer customer);
}

1.2、创建CustomerDao接口类的实现类CustomerDaoImpl

package com.lqg.daoImpl;

import com.lqg.dao.CustomerDao;
import com.lqg.domain.Customer;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class CustomerDaoImpl implements CustomerDao {
    private SqlSessionFactory sqlSessionFactory;
    public CustomerDaoImpl(SqlSessionFactory sqlSessionFactory){
        this.sqlSessionFactory=sqlSessionFactory;
    }
    @Override
    public Customer findCustomerById(Long cust_id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Customer customer = sqlSession.selectOne("queryCustomerById", 2);
        return customer;
    }

    @Override
    public List<Customer> findAllCustomer() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Customer> allCustomer = sqlSession.selectList("queryAllCustomer");
        return allCustomer;
    }

    @Override
    public int saveCustomer(Customer customer) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        int customer1=sqlSession.insert("saveCustomer",customer);
        return customer1;
    }
}

1.3、创建CustomerDao的测试类TestCustomerDao的测试类

package com.lqg.test;

import com.lqg.dao.CustomerDao;
import com.lqg.daoImpl.CustomerDaoImpl;
import com.lqg.domain.Customer;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestCustomerDao {
    private SqlSessionFactory sqlSessionFactory;
    public void init() throws IOException {
        System.out.println("init");
        //1.创建一个SqlSessionFactoryBulider的类
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
         //2.加载SqlMapConfig.xml的配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //3.创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
@Test
public void test(){
		//创建CustomerDao的接口编程
        CustomerDao customerDao = new CustomerDaoImpl(this.sqlSessionFactory);
        //通过id查询用户,然后保存到customer中
        Customer customer = customerDao.findCustomerById(2L);
        System.out.println(customer);
        List<Customer> allCustomer = customerDao.findAllCustomer();
        System.out.println(allCustomer);
    }
}

2.Mapper动态代理

2.1、Mapper动态代理开发的要求

  1. namespace必须和Mapper接口类路径一致
  2. id必须和Mapper接口方法名一致
  3. parameterType必须和接口方法参数类型一致
  4. resultType必须和接口方法返回值类型一致

2.2、先重新创建一张表

CREATE TABLE tbl_employee{
	id INT PRIMARY KEY auto_increment,
	last_name VARCHAR(255),
	gender CHAR(1),
	email VARCHAR(255)
}

2.3、这是演示的结构图
在这里插入图片描述
2.4、创建一个Employee的pojo类

package com.lqg.mybatis.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter@Getter@ToString
public class Employee {

    private Integer id;
    private String lastName;
    private String gender;
    private String email;
}

2.5、创建MyBatis的核心配置文件

<?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>
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/lqg/mybatis/domain/EmployeeMapper.xml"/>
    </mappers>
</configuration>

2.6、创建pojo的接口类

package com.lqg.mybatis.dao;

import com.lqg.mybatis.domain.Employee;

public interface EmployeeMapper {
    public Employee getEmployeeById(Integer id);//方法名称为xml配置文件里面的对应操作语句的id名称
}

2.7、创建pojo的映射EmployeeMapper.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">
<!-- namespace:命名空间,用于隔离sql语句,后续有重要内容 -->

        <!-- 1. namespace必须和Mapper接口类路径一致
         2. id必须和Mapper接口方法名一致
         3. parameterType必须和接口方法参数类型一致
         4. resultType必须和接口方法返回值类型一致-->
<!--public Employee getEmployeeById(Integer id);-->
<mapper namespace="com.lqg.mybatis.dao.EmployeeMapper">
    <select id="getEmployeeById" resultType="com.lqg.mybatis.domain.Employee">
        select id,last_name lastName,gender,email from tbl_employee where id=#{id}
    </select>
</mapper>

2.8、最后编写MyBatisTest的测试类

package com.lqg.mybatis.test;

import com.lqg.mybatis.dao.EmployeeMapper;
import com.lqg.mybatis.domain.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class MyBatisTest {
    @Test
    public void test() throws IOException {
        //1.创建一个SqlSessionFactoryBulider的类
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.加载mybatis-config.xml的配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //3.创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //4.创建SqlSession对象
        SqlSession openSession = sqlSessionFactory.openSession();
        //获取接口的实现类对象
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);//接口的字节码
        Employee employee=mapper.getEmployeeById(1);//方法为接口当中的方法

        System.out.println(employee);
        openSession.close();
    }
}

2.9、查询效果如下
在这里插入图片描述

五、MyBatis的参数传递

1.单个参数

  • 可以接受基本类型,对象类型,集合类型的值。
  • MyBatis可直接使用这个参数,不需要经过任何处理。

2.多个参数

  • 任意多个参数,都会被MyBatis重新包装成一个Map传入。
  • Map的key是param1,param2…,值就是参数的值
    示例
    在这里插入图片描述
    在这里插入图片描述
    3.@param命名参数
  • 为参数使用@Param起一个名字
  • MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字
    示例
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    4.pojo
  • 当这些参数属于我们业务POJO时,我们直接传递POJO
    示例
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    5.Map
    我们也可以封装多个参数为map,直接传递
    示例
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    6.参数传递源码分析
  • 会把参数给放到一个数组当中
  • 如果一个参数, 内部处理时,会自动把该参数范围

在这里插入图片描述

  • 如果是多个参数,内部会做判断
  • 判断是否有@param注解

如果没有

  • 没有注解的话, 就直接使用arg0 arg1…为key 放到map中
    并且还会以param1和param2…为key放一份到map中

在这里插入图片描述
如果有

  • 如果有注解的话, 会使用注解当中的值,替换掉默认的arg0和arg1 使用@param中的值,做为key 放到一个map当中
    并且还会以param1和param2…为key放一份到map中

在这里插入图片描述

六、MyBatis的核心配置文件

1、 properties:定义属性及读取属性文件

示例

 <properties resource="jdbc.properties">
        <property name="jdbc.driver" value="com.mysql.jdbc.Driver"></property>
</properties>

resource为资源文件,配置文件访问方法"${key名称}",如访问数据库连接,如果配置了相同的property会先加载,resource里面的会把其覆盖掉

2、settings——这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
示例

 <!--全局信息配置,-->
    			<settings>
				//配置打印sql信息
       				 <setting name="logImpl" value="STDOUT_LOGGING"/>
    			</settings>

3、typeAliases——(定义别名,可以在使用时候省略掉前面一串路径)

<typeAliases>
       <!--单个别名-->
       <!--<typeAlias type="domain.Customer" alias="Customer"></typeAlias>-->
      <!--批量定义别名,别名为类名-->
       <package name="domain"></package>
</typeAliases>

如果当前包类与子包类重名,会有异常,可以在类上使用注解@Alias(“别名”)

4、typeHandlers——(类型处理器)
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,
还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
JDK1.8之后实现全部的JSR310规范
日期时间处理上,我们可以使用MyBatis基于JSR310(Date and Time API)
编写的各种日期时间类型处理器。
MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的

5、Plugins ——(插件)
插件是MyBatis提供的一个非常强大的机制,
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
通过插件来修改MyBatis的一些核心行为。

6、Environments ——(数据库运行的环境)
MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
每种环境使用一个environment标签进行配置并指定唯一标识符
可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
Environment子标签
transactionManager事务管理
Type有以下取值
JDBC
使用JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
MANAGED
不提交或回滚一个连接、让容器来管理事务的整个生命周期
ManagedTransactionFactory
自定义
实现TransactionFactory接口
type=全类名/别名
dataSource数据源
type有以下取值
UNPOOLED
不使用连接池UnpooledDataSourceFactory
POOLED
使用连接池PooledDataSourceFactory
JNDI
在EJB 或应用服务器这类容器中查找指定的数据源
自定义
实现DataSourceFactory接口,定义数据源的获取方式
实际开发
实际开发中我们使用Spring管理数据源
并进行事务控制的配置来覆盖上述配置

7、databaseIDProvider——(定义数据的厂商)
MyBatis 可以根据不同的数据库厂商执行不同的语句。
可以能过databaseIDProvider标签来进行设置

<databaseIdProvider type="DB_VENDOR">
	     <property name="MYSQL" value="mysql"/>
		 <property name="DB2" value="db2"/>
		 <property name="Oracle" value="oracle" />
         <property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
	示例
<mapper namespace="mapper.CustomerDao">
    	<select id="getCustomerWithID"  resultType="Customer" databaseId="mysql">	//只有Mysql的数据库才能执行该语句
         select * from customer where cust_id = #{id名称} and cust_name=#{}
    	</select>
</mapper>
			

8、mappers——(加载映射文件)
8.1、使用文件路径引入映射器

 <mapper resource="domain/Customer.xml"></mapper>		

8.2、使用mapper接口类路径,此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中

<mapper class=" " /><mapper class="mapper.CustomerDao">
</mapper>

8.3、使用包名引入映射器
指定包下的所有mapper接口、批量加载、此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中

<package name=""/

//加载对应包下面所有的文件

七、MyBatis的输出类型

八、MyBatis【关联映射】

1、MyBatis的多表连接

1.1一对一

在这里插入图片描述

1.1.1设计表格:
--mysql

create table cards(
    cid int(5) primary key,
    cnum varchar(10)
);

create table students(
    sid int(5) primary key,
    sname varchar(10),
    scid int(5),
    constraint scid_fk foreign key(scid) references cards(cid)
);

insert into cards(cid,cnum) values(1,'111');
insert into students(sid,sname,scid) values(1,'哈哈',1);

select * from cards;
select * from students;
1.1.2、实体类
/**
 * 身份证(单方)
 * @author AdminTC
 */
public class Card {
    private Integer id;
    private String num;
    public Card(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getNum() {
        return num;
    }
    public void setNum(String num) {
        this.num = num;
    }
}
/**
 * 学生(单方)
 * @author AdminTC
 */
public class Student {
    private Integer id;
    private String name;
    private Card card;//关联属性
    public Student(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Card getCard() {
        return card;
    }
    public void setCard(Card card) {
        this.card = card;
    }
}
1.1.3、映射文件

由于我们有两个实体,因此我们会有两个映射文件
Student映射文件

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

    <resultMap type="zhongfucheng2.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
    </resultMap>
</mapper>

Card映射文件

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

    <resultMap type="zhongfucheng2.Card" id="cardMap">
        <id property="id" column="cid"/>
        <result property="num" column="cnum"/>
    </resultMap>    
</mapper>
select * from zhongfucheng.students s,zhongfucheng.cards c where c.cid = s.scid and sid=1;

我来看一下查询结果:
在这里插入图片描述
我们的实体与映射表中,Student实体是没有关联其他的字段的,仅仅是写出了该实体的自带的属性。

    <resultMap type="zhongfucheng2.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
    </resultMap>

明显地,我们Student是不能封装返回的结果,因此我们需要将关联属性进行关联起来!

  <resultMap type="zhongfucheng2.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>

        <!--
            property写的是在Student实体中写关联字段的属性变量名称
            resultMap写的是映射文件中的命名空间.id
        -->
        <association property="card" resultMap="cardNamespace.cardMap"/>
    </resultMap>

我们关联了以后,Student实体就能够封装返回的结果了

<!-- 因为使用多表联合查询,
		  那么查询结果中的列在对象中就没有对应的属性
		  所以需要我们自己去配置这些列与对象中的属性的映射关系	
		  注意:并且需要给所有属性配置映射关系  
	 -->
    <resultMap type="zhongfucheng2.Student" id="studentMap">
    <!-- id子标签:用于配置主键的映射关系 ,这个id是下面的id
		column:查询结果中的列的列名
		property:结果对象中的属性名
		把列与属性之间关联起来:会把查询到的该列的值赋值给这个属性
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>

        <!--
            property写的是在Student实体中写关联字段的属性变量名称
            resultMap写的是映射文件中的命名空间.id
        -->
        <!-- 封装该对象的属性 与 查询语句结果的列的映射 关系 -->
        <association property="card" resultMap="cardNamespace.cardMap"/>
    </resultMap>

    <select id="findById" parameterType="int" resultMap="studentMap">
        select * from zhongfucheng.students s,zhongfucheng.cards c where c.cid = s.scid and sid=#{id};
    </select>
1.1.4查询编号为1的学生信息【包括身份证编号】

    public Student findById(int id) throws Exception {
        //得到连接对象
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{

            return sqlSession.selectOne("studentNamespace.findById", id);

          /*  sqlSession.commit();*/
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = studentDao.findById(1);

        System.out.println(student.getId() + "----" + student.getName() + "----" + student.getCard().getNum());

    }

在这里插入图片描述 这里写图片描述

2.1一对多

在这里插入图片描述

2.1.1设计数据库表
create table grades(
  gid int(5) primary key,
  gname varchar(10)
);

create table students(
  sid int(5) primary key,
  sname varchar(10),
  sgid int(5),
  constraint sgid_fk foreign key(sgid) references grades(gid)
);

insert into grades(gid,gname) values(1,'java');

insert into students(sid,sname,sgid) values(1,'哈哈',1);
insert into students(sid,sname,sgid) values(2,'呵呵',1);


select * from grades;
select * from students;
2.1.2创建实体类
package zhongfucheng2;

import java.util.ArrayList;
import java.util.List;

/**
 * 学科(单方)
 * @author AdminTC
 */
public class Grade {
    private Integer id;
    private String name;
    private List<Student> studentList = new ArrayList<Student>();//关联属性
    public Grade(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Student> getStudentList() {
        return studentList;
    }
    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }
}
package zhongfucheng2;

/**
 * 学生(多方)
 * @author AdminTC
 */
public class Student {
    private Integer id;
    private String name;
    private Grade grade;//关联属性
    public Student(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}
2.1.3映射文件SQL语句
<mapper namespace="studentNamespace">

    <resultMap type="zhongfucheng2.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
    </resultMap>


    <!--查询选修的java学科有多少位学生-->

    <!--由于我们只要查询学生的名字,而我们的实体studentMap可以封装学生的名字,那么我们返回studentMap即可,并不需要再关联到学科表-->
    <select id="findByGrade" parameterType="string" resultMap="studentMap">

        select s.sname,s.sid from zhongfucheng.students s,zhongfucheng.grades g WHERE s.sgid=g.gid and g.gname=#{name};


    </select>

</mapper>



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

    <resultMap type="zhongfucheng2.Grade" id="gradeMap">
        <id property="id" column="gid"/>
        <result property="name" column="gname"/>
    </resultMap>
</mapper>
2.1.4DAO
public List<Student> findByGrade(String  grade) throws Exception {
        //得到连接对象
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{

            return sqlSession.selectList("studentNamespace.findByGrade", grade);
          /*  sqlSession.commit();*/
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        List<Student> student = studentDao.findByGrade("java");

        for (Student student1 : student) {
            System.out.println(student1.getName());
        }
    }

在这里插入图片描述

1.3多对多

在这里插入图片描述

1.3.1数据库表

create table students(
    sid int(5) primary key,
    sname varchar(10)
);

create table courses(
    cid int(5) primary key,
    cname varchar(10)
);

create table middles(
    msid int(5),
    mcid int(5),
    primary key(msid,mcid)
);

insert into students(sid,sname) values(1,'哈哈');
insert into students(sid,sname) values(2,'呵呵');

insert into courses(cid,cname) values(1,'java');
insert into courses(cid,cname) values(2,'android');

insert into middles(msid,mcid) values(1,1);
insert into middles(msid,mcid) values(1,2);
insert into middles(msid,mcid) values(2,1);
insert into middles(msid,mcid) values(2,2);

select * from students;
select * from courses;
select * from middles;

1.3.2 创建实体类

package cn.itcast.javaee.mybatis.many2many;

import java.util.ArrayList;
import java.util.List;

/**
 * 课程(多方)
 * @author AdminTC
 */
public class Course {
    private Integer id;
    private String name;
    private List<Student> studentList = new ArrayList<Student>();//关联属性
    public Course(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Student> getStudentList() {
        return studentList;
    }
    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }
}
package cn.itcast.javaee.mybatis.many2many;

import java.util.ArrayList;
import java.util.List;

/**
 * 学生(多方)
 * @author AdminTC
 */
public class Student {
    private Integer id;
    private String name;
    private List<Course> courseList = new ArrayList<Course>();//关联属性
    public Student(){}
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Course> getCourseList() {
        return courseList;
    }
    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }
}

1.3.3映射文件

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

    <resultMap type="cn.itcast.javaee.mybatis.many2many.Course" id="courseMap">
        <id property="id" column="cid"/>
        <result property="name" column="cname"/>
    </resultMap>    



    <!-- 查询哈哈选学了哪些课程 -->
    <select id="findAllByName" parameterType="string" resultMap="courseMap">
        select c.cid,c.cname
        from students s inner join middles m
        on s.sid = m.msid
        inner join courses c
        on m.mcid = c.cid
        and s.sname = #{name}
    </select>

</mapper>
<?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="studentNamespace">

    <resultMap type="cn.itcast.javaee.mybatis.many2many.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
    </resultMap>    


    <select id="findAllByCourseName" parameterType="string" resultMap="studentMap">
        select s.sname
        from students s inner join middles m
        on s.sid = m.msid 
        inner join courses c
        on m.mcid = c.cid
        and c.cname = #{name}
    </select>

</mapper>

1.3.4创建DAO

package cn.itcast.javaee.mybatis.many2many;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import cn.itcast.javaee.mybatis.util.MybatisUtil;

/**
 * 持久层
 * @author AdminTC
 */
public class StudentCourseDao {
    /**
     * 查询哈哈选学了哪些课程
     * @param name 表示学生的姓名
     */
    public List<Course> findAllByName(String name) throws Exception{
        SqlSession sqlSession = null;
        try{
            sqlSession = MybatisUtil.getSqlSession();
            return sqlSession.selectList("courseNamespace.findAllByName",name);
        }catch(Exception e){
            e.printStackTrace();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    /**
     * 查询java课程有哪些学生选修
     * @param name 表示学生的课程
     */
    public List<Student> findAllByCourseName(String name) throws Exception{
        SqlSession sqlSession = null;
        try{
            sqlSession = MybatisUtil.getSqlSession();
            return sqlSession.selectList("studentNamespace.findAllByCourseName",name);
        }catch(Exception e){
            e.printStackTrace();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }






    public static void main(String[] args) throws Exception{
        StudentCourseDao dao = new StudentCourseDao();
        List<Course> courseList = dao.findAllByName("哈哈");
        System.out.print("哈哈选学了" + courseList.size()+"个课程,分别是:");
        for(Course c : courseList){
            System.out.print(c.getName()+" ");
        }
        System.out.println("\n-----------------------------------------------------");
        List<Student> studentList = dao.findAllByCourseName("android");
        System.out.println("选修了android课程的学生有"+studentList.size()+"个,分别是:");
        for(Student s : studentList){
            System.out.print(s.getName()+" ");
        }
    }
}

九、MyBatis的动态sql语句

1.什么是动态sql:

通过mybatis提供的各种标签方法实现动态拼接sql。

1、if标签

需求:根据客户名和级别查询客户

<!--根据客户名和级别查询客户-->
<select id="queryCustomerWhere" parameterType="customer" resultType="customer">
	select * from cst_customer where cust_name=#{cust_name} and cust_level=#{cust_level}
</select> 

存在问题

  • 有可能传入的名称或级别为空
  • 可以使用if标签来进行判断

注意:test:放的是Boolean表达式

<select id="queryCustomerWhere" parameterType="customer" resultType="customer">
	select * from cst_customer where 
	<if test="cust_name !=null and cust_name=''">
		cust_name=#{cust_name}
	</if>
	<if test="cust_level !=null and cust_name=''">
		And cust_level=#{cust_name}
	</if>
</select> 

如果前一个条件这后,后面就会多一个and执行就会报错

2、Where标签

where标签可以自动添加where,同时可以处理sql语句中第一个and关键字

<select id="queryCustomerWhere" parameterType="customer" resultType="customer">
	select * from cst_custome
   <where>
	<if test="cust_name !=null and cust_name=''">
		cust_name=#{cust_name}
	</if>
	<if test="cust_level !=null and cust_name=''">
		And cust_level=#{cust_name}
	</if>
  </where>
</select> 

去掉第一个前And

3、trim标签

  1. prefix:设置前缀,在第一个条件之前加上一个前缀
  2. prefixOerrides:条件前缀覆盖,把第一个条件之前的and变成空
  3. suffix:设置后缀,在最后一个条件之后加上一个后缀
  4. suffixOverrides:条件后缀覆盖,把最后一个条件之后的and变成空
 <select id="getCustomer" resultType="domain.Customer">
        		select * from `customer`
        		<trim prefix="where" prefixOverrides="and" suffixOverrides="" suffix="and">
            			<if test="name!=null and name!=''">
                			and cust_name=#{name}
            			</if>
            			<if test="profession!=null and profession!=''">
               			 	and  cust_profession=#{profession}
            			</if>
        		</trim>
</select>

DAO层
现在我想根据学生的编号查询学生的信息和身份证信息!

由于该查询着重是查询学生的信息,于是我们在学生的映射文件中写SQL语句

按照需求,我们写出来的SQL语句是这样子的

4、choose标签

choose用法基本和if一致

sql
sql
sql

注意:整个choose最终只会匹配一种情况

when
choose标签:(只查满足条件的第一个,后面的条件都不执行) select * from customer

<where>
            		<choose>
                		<when test="profession!=null and profession!=''">
                    			cust_profession=#{profession}
                		</when>
                		<when test="name!=null and name!=''">
                    			cust_name=#{name}
                		</when>
                		<otherwise>1=1</otherwise>	//当都没有满足条件的时候,执行该默认语句
            		</choose>
</where>

5、set标签

6、foreach

向sql传递数据或List,mybatis使用foreach解析,如下
根据多个id查询用户信息
查询sql:select * from user where id in(1,10,24)
在pojo中定义list属性ids存储多个用户id,并添加getter/settter方法

@Getter@Setter@ToString
public class QueryVo{
//包含其他的pojo
private User user;
private list<Integer> ids;

Mapper.xml文件

<!--根据ids查询用户-->
<select id="queryUserByIds" parameterType="queryVo" resultType="user">
	select * from user 
	<where>
	<!--foreach标签,进行遍历-->
	<!--collection:遍历的集合,这里是queryVo的ids的属性值->
	<!--遍历的项目,可以随便写,但是和后面的#{}里面要保持一致-->
	<!--open:在前面添加sql片段-->
	<!--separator:指定遍历元素之间的分隔符-->
		<foreach collection="ids" item="item" open="id IN("close =")" separator=",">
			#{item}
		</foreach>
	</where>
</select>

7、bind

用于绑定一个字符,并且取名

8、Sql片段

使用include标签加载sql片段,refid是sql片段的id
如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的nameSpace
如:

<include refid="com.lqg.mybatis.mapper.OrderMapper.userFirlds"/>
<select id="queryCustomerWhere" parameterType="customer" resultType="customer">
	select <include refid="userFirlds"/> from cst_custome
   <where>
	<if test="cust_name !=null and cust_name=''">
		cust_name=#{cust_name}
	</if>
	<if test="cust_level !=null and cust_name=''">
		And cust_level=#{cust_name}
	</if>
  </where>
</select> 
<!--声明sql片段-->
<sql id="userFieleds">
	cust_id,cust_name,cust_level 	
</sql>

猜你喜欢

转载自blog.csdn.net/qq_43674132/article/details/90047789