mybatis框架(进阶篇)

本文详细介绍了MyBatis的Dao模式,包括数据存取对象的概念、基于代理Dao实现的CRUD操作,如查询、保存、更新和删除用户的方法。通过配置XML映射文件,设置查询结果列名与实体类属性的对应关系,实现动态SQL。此外,还讲解了MyBatis的事务管理和连接池配置,以及如何在测试类中进行操作。
摘要由CSDN通过智能技术生成

Dao模式(Data Access Objects)[数据存取对象]

基于代理Dao实现CRUD操作(重点)

配置查询结果的列名和实体类的属性名的对应关系
<resultMap id="userMap" type="com.example.domain.User">
    <!--主键字段的对应-->
    <id property="userId" column="id"></id>
    <!--非主键字段的对应-->
    <result property="userName"  column="username"></result>
    <result property="userAddress"  column="address"></result>
    <result property="userSex"  column="sex"></result>
    <result property="userBirthday"  column="birthday"></result>
</resultMap>
查询操作
  • 查询所有用户:List<User> findAll();
<select id="findAll" resultMap="userMap">
    <!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
    select * from ;
</select>
  • 根据id查询用户:User findById(Integer userId);
<select id="findById" parameterType="INT" resultMap="userMap">
    select * from  user where id = #{uid};
</select>
  • 根据名称模糊查询:List<User> findByName(String username);
<select id="findById" parameterType="INT" resultMap="userMap">
    select * from  user where id = #{uid};
</select>
  • 查询总用户数:int findTotal();
<select id="findTotal" resultMap="userMap">
    select count(id) from user;
</select>
  • 根据queryVo的条件查询用户:List<User> findUserByVo(Query vo);
<select id="findUserByVo" parameterType="com.example.domain.QueryVo">
    select * from  user where username like #{user.username}
</select>
保存操作
  • 保存用户:void saveUser(User user);
<insert id="saveUser" parameterType="user">
    <!-- 配置插入操作,获取插入数据的id -->
    <!-- keyProperty(id的属性名称对应实体类)keyColumn(id的列名对应表)resultType(结果值类型)order(什么时候执行获取id的操作) -->
    <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
    insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
</insert>
更新操作
  • 更新用户:void updateUser(User user);
<update id="updateUser" parameterType="com.example.domain.User">
    update user set username=#{userName},address=#{userAddress},sex=#{userSex},birthday=#{userBirthday} where id=#{userId};
</update>
删除操作
  • 根据id删除用户:User findById(Integer userId);
<delete id="deleteUser" parameterType="java.lang.Integer">
    delete from user where id = #{uid}
</delete>

Mybatis基于传统dao方式的使用(了解)

持久层Dao接口:
public interface UserDao {
    
    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();
    
        /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);
    }
    
持久层Dao实现类:
import com.example.dao.UserDao;
import com.example.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class UserDaoImpl implements UserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public List<User> findAll() {
        //1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2. 调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("findAll22");//参数就是能获取配置信息的key
//        UserDao userDao = session.getMapper(UserDao.class);
//        List<User> users = userDao.findAll();
        //3. 释放资源
        session.close();
        return users;
    }
    
        @Override
    public User findById(Integer userId) {
        //1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2. 调用SqlSession中的方法,实现查询一个
        User users = session.selectOne("findById");
        //3. 释放资源
        session.close();
        return users;
    }
    }
持久层映射配置:
<?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.example.dao.UserDao">




    <!-- 查询所有 -->
    <select id="findAll" resultType="com.example.domain.User">
        <!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
        select * from user;
    </select>

    <select id="findById" resultType="com.example.domain.User">
        select
    </select>

</mapper>
测试类:
import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;
import com.example.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

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

public class MybatisTest {

    private InputStream is;
    private SqlSession session;
    private UserDao userDao;
    @Before//用于测试方法执行之前执行
    public void init() throws Exception {
        System.out.println("1");


        //1. 读取配置文件,生成字节输入流
         is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. 获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3. 使用工厂对象,创建dao对象
         userDao = new UserDaoImpl(factory);
    }

    @After//用于测试方法执行之后执行
    public void destroy() throws Exception{
        //6.  释放资源
        is.close();
    }
    /**
     *测试查询所有
     */
    @Test
    public void testFindAll()  {
        //5. 执行查询所有方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }

    }
    }

mybatis主配置文件中的常用配置

  • properties标签:配置数据库信息。
  • typeAliases标签:解释Integer的写法
  • mapper标签的子标签:package
<?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>

    <properties resource="jddbcConfig.properties"></properties>
    <typeAliases>
        <typeAlias type="com.example.domain.User" alias="user"></typeAlias>

        <package name="com.example.domain"></package>
    </typeAliases>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>

            <!-- 配置连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件的位置 -->
    <mappers>
<package name="com.example.dao"></package>
    </mappers>
</configuration>

自定义mybatis流程图

在这里插入图片描述

扩展知识:{}与${}的区别
  • #{}表示一个占位符号

通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,

{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。

  • ${}表示拼接 sql串

通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简

mybatis中的连接池以及事务控制:

  • 在mybatis的SqlMapConfig.xml配置文件中,通过<dataSource type="pooled">
连接池:
  • 连接池: 在实际开发中均使用连接池,主要目的是减少获取连接所消耗的时间。
mybatis中的连接池:

mybatis连接池提供的三种配置方法:

  • 配置的位置:主配置文件SqlMapConfig.xml中的dataSource标签。
  • type属性的取值:
  1. POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
  2. UNPOOLED 采用传统的获取连接的方式,实现了Javax.sql.DataSource接口,但并没有使用池的思想。
  3. JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource不同。

注意
如果不是web或者maven的war工程,是不能使用的(tomcat服务器,采用连接池就是dbcp连接池。)

Mybatis连接池及事务控制

连接池
  1. 连接池概念:创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。
  2. 连接池的核心思想:连接复用,通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。(减少获取连接所消耗的时间)
Mybatis的连接池
  • 数据源的作用:更好的管理数据库连接,即为连接池技术。
    type属性的取值
type属性(采用哪种连接池方式)注解
POOLED使用连接池的数据源,直接从连接池获取数据源使用(主要)
UNPOOLED不使用连接池的数据源,创建一个新的数据源使用
JNDI使用 JNDI 实现的数据源(不同的服务器得到的数据源不同)

注意:当所创建的为web或maven的war工程时才能使用。

  • POOLED与UNPOOLED区别

  • 连接池配置位置:主配置文件SqlMapConfig.xml的dataSource标签中。

<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>
Mybatis中的事务
  • 事务(Transaction):访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
  • 事务的四大特性(ACID):原子性、一致性、隔离性、持久性
特性注解
原子性(atomicity)事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
一致性(consistency)事务必须是使数据库从一个一致性状态变到另一个一致性状态。
隔离性(isolation)一个事务的执行不能被其他事务干扰。
持久性(durability)一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
  • 不考虑隔离性会产生的三大问题

脏读:A事务中读取到了B事务中未提交的数据,造成数据错误。
不可重复读:A事务中读取到了B事务中已提交的数据,在特定情景下会产生影响,比如生成统一的数据报表。
虚读(幻读):A事务中读取到了B事务中已提交的新插入的数据。

  • 解决办法:四种隔离级别
    在这里插入图片描述
  • 注:事务通过SqlSession对象的commit方法和rollback方法实现事务的提交和回滚。
基于XML配置的动态SQL语句使用

<if>:条件查询

<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like #{username}
</if> <if test="address != null">
and address like #{address}
</if>
</select>

<where>:简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。

<select id="findByUser" resultType="user" parameterType="user"> <include refid="defaultSql"></include> <where> <if test="username!=null and username != '' ">
and username like #{username}
</if> <if test="address != null">
and address like #{address}
</if>
</where>
</select>

<foreach>:用于遍历集合

<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); --> <include refid="defaultSql"></include> <where> <if test="ids != null and ids.size() > 0"> <foreach collection="ids" open="id in ( " close=")" item="uid" 
separator=",">
#{uid}
</foreach>
</if>
</where>
</select>

<sql>:可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。

<!-- 抽取重复的语句代码片段 --> 
<sql id="defaultSql">
select * from user
</sql>
<!-- 配置查询所有操作 --> <select id="findAll" resultType="user"> <include refid="defaultSql"></include>
</select>
Mybatis中的多表查询
  • 表之间的关系
  • 多对一:多门课程对应一个专业

例如:

  • 需求:查询所有账户信息,关联查询下单用户信息。
  • 注意:因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。
/**
账户的实体类
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;

public Integer getId() {
return id; }
public void setId(Integer id) {
this.id = id; }
public Integer getUid() {
return uid; }
public void setUid(Integer uid) {
this.uid = uid; }
public Double getMoney() {
return money; }
public void setMoney(Double money) {
this.money = money; }
@Override
public String toString() {
return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]"; } }
public class AccountUser extends Account implements Serializable {
private String username;
private String address;
public String getUsername() {
return username; }
public void setUsername(String username) {
this.username = username; }
public String getAddress() {
return address; }
public void setAddress(String address) {
this.address = address; }
@Override
public String toString() {
return super.toString() + " AccountUser [username=" + username + ", 
address=" + address + "]"; } }
/**
 账户的持久层接口
 */
 public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<AccountUser> findAll();
}
/**
定义 AccountDao.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.itheima.dao.IAccountDao">
<!-- 配置查询所有操作--> <select id="findAll" resultType="accountuser">
select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select> </mapper>
/**
创建 AccountTest 测试类
*/
public class AccountTest {
private InputStream in ;
private SqlSessionFactory factory;
private SqlSession session;
private IAccountDao accountDao;
@Test
public void testFindAll() {
//6.执行操作
List<AccountUser> accountusers = accountDao.findAll();
for(AccountUser au : accountusers) {
System.out.println(au);
} }
@Before//在测试方法执行之前执行
public void init()throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.创建 SqlSession 工厂对象
factory = builder.build(in);
//4.创建 SqlSession 对象
session = factory.openSession();
//5.创建 Dao 的代理对象
accountDao = session.getMapper(IAccountDao.class);
}
@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
session.commit();
//7.释放资源
session.close();
in.close();
} }

步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系
3、建立两个配置文件
用户的配置文件
账户的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息

  • 一对一:学生与学号
  • 多对多:学生与教师
  • 一对多:订单与客户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值