【MyBatis】mybatis入门

1. 环境配置

1.1 引入依赖或直接添加jar包
 <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.17</version>
 </dependency>
 <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.12</version>
     <scope>test</scope>
 </dependency>

 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.6</version>
     <scope>runtime</scope>
 </dependency>

 <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis</artifactId>
     <version>3.4.5</version>
 </dependency>
1.2 项目目录结构

在这里插入图片描述

1.3 数据表创建

-- ----------------------------
-- Table structure for `account`
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(11) NOT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('1', '1', '1000');
INSERT INTO `account` VALUES ('2', '1', '2000');
INSERT INTO `account` VALUES ('3', '2', '2000');
INSERT INTO `account` VALUES ('4', '3', '30');

-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rolename` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', '狗头军师');
INSERT INTO `role` VALUES ('2', '千年咸鱼');
INSERT INTO `role` VALUES ('3', '吃瓜群众');

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '张三', '18');
INSERT INTO `user` VALUES ('2', '李四', '21');
INSERT INTO `user` VALUES ('3', '张待遇', '30');
INSERT INTO `user` VALUES ('4', '张哈哈', '12');
INSERT INTO `user` VALUES ('5', '张大炮', '30');

-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(11) NOT NULL,
  `roleid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1', '1');
INSERT INTO `user_role` VALUES ('2', '1', '2');
INSERT INTO `user_role` VALUES ('3', '1', '3');
INSERT INTO `user_role` VALUES ('4', '2', '1');
INSERT INTO `user_role` VALUES ('5', '2', '2');
INSERT INTO `user_role` VALUES ('6', '3', '1');
INSERT INTO `user_role` VALUES ('7', '5', '2');
1.4 日志配置
  • 把log4j.properties文件添加到resources根目录下即可,控制台会打印mybatis的sql语句
#  LOGFILE把日志记录在文件中
#log4j.rootCategory=debug, CONSOLE, LOGFILE
log4j.rootCategory=debug, CONSOLE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# 如果上面rootCategory启用了LOGFILE,需要把下面注释解开才能把日志记录在文件中
#log4j.appender.LOGFILE=org.apache.log4j.FileAppender
#log4j.appender.LOGFILE.File=d:\axis.log
#log4j.appender.LOGFILE.Append=true
#log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
#log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

2. 入门配置

2.1 实体类
package com.domain;

public class User {
    private Integer id;
    private String username;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

2.2 Dao接口
package com.dao;
import com.domain.User;
import java.util.List;

public interface IUserDao {
    List<User> findAll();
    User findById(int id);
}
2.3 Dao映射文件
  • 映射文件要跟Dao文件在同一目录下
  • 映射文件的目录创建时只能只能只能一次创建一层文件夹,不能跟包一样带点.创建多层,否则半天都找不到运行错误的原因
  • 建议把包设置分层显示,避免看错文件夹层次
<?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指向的是Dao接口 -->
<mapper namespace="com.dao.IUserDao">

    <!-- 该方法虽然返回的是List<User>,但这里还是要填写实体类User,而不是List -->
    <select id="findAll" resultType="com.domain.User">
        select * from user;
    </select>


    <!-- select标签id属性要跟Dao接口中的方法名一样 -->
    <!-- parameterType是方法参数类型,该属性写不写都可以 -->
    <!-- resultType是返回值类型 -->
    <!-- parameterType和resultType默认都要带上包名,但可以通过主配置文件设置别名 -->
    <!--  int,String,date等常用类型mybatis已经默认设置了别名,而且不区分大小写 -->
    <select id="findById" parameterType="iNt" resultType="com.domain.User">
        <!-- 如果方法参数是单个基本类型值,则可用 #{随便一个名字} 作为占位符,作用等同于?占位符 -->
        select * from user where id=#{userId}
    </select>
</mapper>

在这里插入图片描述

2.4 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>

    <!-- 数据库连接信息 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis03"/>
                <property name="username" value="root"/>
                <property name="password" value="root"></property>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 指定映射文件存放的包 -->
        <package name="com.dao"/>

    <!--
        指定单个映射文件
        这两个mapper作用一样的,dao接口名字要跟映射文件名字相同
        <mapper class="com.dao.IUserDao"/>
        作用同上
        <mapper resource="com/dao/IUserDao.xml"/>
    -->
    </mappers>
</configuration>
2.5 测试
       //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        // 2.创建 SqlSessionFactory 的构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 3.使用构建者创建工厂对象
        SqlSessionFactory factory = builder.build(in);
        // 4.使用 SqlSessionFactory 生产 SqlSession 对象
        SqlSession session = factory.openSession();
        // 5.使用 SqlSession 创建 dao 接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        // 6.使用代理对象执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users) {
            System.out.println(user);
        }

        User user=userDao.findById(1);
        System.out.println("findById:"+user);
        // 7.释放资源
        session.close();
        in.close();

3. 方法参数与返回值深入理解

3.1 单个基本类型作为方法参数
  • #{名字}是作为参数的占位符,如果方法参数只有一个,并且该参数为基本类型,则名字随意起,不用跟方法参数的形参名字一样,等同一个sql占位符?,防sql注入,但实际中尽量还是跟方法参数名字一致,方便阅读

  • ${value} 固定写法,名字必须是value,是作为一个变量跟sql语句直接拼接字符串,可能会出现sql注入问题


<!-- 接口方法User findById(int id) -->
<select id="findById" parameterType="iNt" resultType="com.domain.User" >
 	<!-- #{}名字可以不跟方法参数名一样 -->
     select * from user where id=#{userId}

	<!-- 等同于"select * from user where id="+id -->
     select * from user where id=${value}
 </select>
3.2 使用多个基本类型作为方法参数
  • xml方式:
    • 使用@Param注解设置占位符的名称(推荐)
    • 使用#{下标}参数下标作为占位符(不要使用,方法参数修改导致影响大,而且暂时测试不成功)
// 1.使用@Param("参数名")设置占位符的名称,一般跟方法参数名一致
List<User> findByAge(@Param("minAge") int minAge,@Param("maxAge") int maxAge);

// 2.在xml的sql中直接使用@Param定义的参数名作为占位
// 多个参数时select标签不用设置parameterType属性
<select id="findByAge" resultType="com.domain.User">
    select * from user where age between #{minAge} and #{maxAge}
</select>
  • 注解方式:直接根据方法参数名作为占位符名字
    // #{param1}或#{id}为第一个占位符
    // #{param2}或#{count}为第二个占位符
    @Update("update tb_template set spec_num=spec_num+#{count} where id=#{id}")
    public void updateSpecNum(int id, int count);
3.3 使用Map作为方法参数
List<User> findByMap(Map<String,Object> map);
<!-- #{key}占位符名称对应Map的key -->
<select id="findByMap" parameterType="java.util.Map" resultType="com.domain.User">
    select * from user where username like #{username} and age=#{age}
</select>
Map<String,Object> map=new HashMap<String, Object>();
map.put("username","%张%");
map.put("age",30);
List<User> userList = userDao.findByMap(map);
for (User user : userList) {
    System.out.println(user);
}
3.4 使用对象作为方法参数
  • 对象可以是实体类也可以自己定义的pojo类(带getter和setter方法)
  • #{类属性名}获取类属性值作为sql参数的值,如果类属性是引用类型,则可以通过.来获取该引用类型属性的属性

自定义条件类

package com.domain;
public class UserCondition {
    //基本类型
    private int minAge;
    private int maxAge;
    //引用类型
    private User user;

    public int getMinAge() {
        return minAge;
    }

    public void setMinAge(int minAge) {
        this.minAge = minAge;
    }

    public int getMaxAge() {
        return maxAge;
    }

    public void setMaxAge(int maxAge) {
        this.maxAge = maxAge;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

映射文件

<!-- 使用条件对象作为方法参数 -->
<select id="findByCondition" parameterType="com.domain.UserCondition" resultType="com.domain.User">
    <!-- CDATA是用来忽略sql语句中在xml中的特殊符号 -->
    <!-- #{类属性名}获取类属性值作为sql参数的值 -->
    <![CDATA[
      select * from user where username like #{user.username} and age>#{minAge} and age<#{maxAge};
    ]]>
</select>

测试

User user=new User();
user.setUsername("%张%");

UserCondition userCondition = new UserCondition();
userCondition.setMinAge(10);
userCondition.setMaxAge(20);
userCondition.setUser(user);

List<User> list=userDao.findByCondition(userCondition);
for (User u : list) {
    System.out.println(u);
}
3.5 使用resultType指定返回值类型
  • resultType可以指定基本类型和引用类型的返回值
  • 例子看上面
3.6 使用resultMap指定查询结果的映射规则
  • id标签是主键列,result标签是普通列
  • association标签和collection标签用于配置一对多关系,详细说明看后面
  • property表示类的的属性,column表示列名
  • jdbcType表示类的的属性的类型,不常用,值只能是org.apache.ibatis.type.JdbcType中的枚举值
    <!-- 定义查询结果映射类对象规则 -->
    <!-- id表示唯一的名字,被其他select标签引用 -->
    <!-- type表示需要映射的类 -->
    <resultMap id="userMap" type="com.domain.User">
        <!-- 主键列 -->
        <id property="id" column="id" ></id>

        <!-- 把username列映射进User类的uname属性中 -->
        <result property="uname" column="username" ></result>

        <!-- 如果不指定映射关系的列和属性,则默认规则进行映射 -->
        <!-- 这条映射规则可以不用写,因为mybatis默认按名字和自身的类型进行映射 -->
        <result property="age" column="age" jdbcType="INTEGER"></result>
    </resultMap>

    <!-- 使用自定义查询结果封装规则作为返回值 -->
    <select id="findAll" resultMap="userMap">
        select * from user;
    </select>
</resultMap>

4.映射文件其他说明

4.1 插入数据获取主键值
<insert id="save" parameterType="com.domain.User">
    <!-- keyProperty主键属性名,keyColumn主键列名,resultType返回值类型 -->
    <selectKey keyProperty="id" keyColumn="id" resultType="int">
        <!-- 查询最近插入的数据的主键值(mysql可用,oracle不可用,oracle可以查询序列获取主键值)-->
        select last_insert_id();
    </selectKey>
    insert into user values(null,#{username},#{age})
</insert>
4.2 定义sql片段重复引用
<!-- 定义sql片段 -->
<!-- 注意别引用分号;结尾 -->
<sql id="defaultSql">
    select * from user
</sql>

<select id="findById" parameterType="int" resultType="user" >
    <!-- 引用sql片段 -->
    <include refid="defaultSql"></include>
    where id=#{userId}
</select>

5. mybatis主配置文件

5.1 配置项和顺序
-properties(属性)
	--property
-settings(全局配置参数)
	--setting
-typeAliases(类型别名)
	--typeAliase
	--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
	--environment(环境子属性对象)
		---transactionManager(事务管理)
		---dataSource(数据源)
-mappers(映射器)
	--mapper
	--package
5.2 properties(属性变量)
  • 在properties标签内使用property标签定义属性变量
<properties>
     <property name="db.username" value="root"/>
     <property name="db.password" value="root"/>
 </properties>
  • 在外部properties文件中定义属性变量
//db.properties文件内容
db.username=root
db.password=root
<!-- 引入外部属性文件 -->
<properties resource="db.properties"> </properties>
  • 使用${}调用属性变量
 <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis03"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"></property>
            </dataSource>
        </environment>
    </environments>
5.3 typeAliases(类型别名)
  • 定义别名
<typeAliases>
    <!-- 定义单个类的别名 -->
    <typeAlias  alias="User" type="com.domain.User"></typeAlias>

    <!-- 定义指定包下所有类的别名,别名为类名,不区分大小写 -->
    <package name="com.domain"/>
</typeAliases>
  • parameterType与resultType都可以使用别名
<!-- com.domain.User别名变成了user -->
<select id="findById" parameterType="iNt" resultType="user" >
    select * from user where id=#{userId}
</select>
5.4 全局配置参数settings
  • 主要用于延迟加载和缓存参数配置,详情查看后面,这里不概述
5.5 映射器mappers
<mappers>
      <!-- 指定映射文件存放的包 -->
      <package name="com.dao"/>

  <!--
      指定单个映射文件
      这两个mapper作用一样的,dao接口名字要跟映射文件名字相同
      <mapper class="com.dao.IUserDao"/>
      作用同上
      <mapper resource="com/dao/IUserDao.xml"/>
  -->
  </mappers>
5.6 插件plugins
  • 参考7.2

6. 使用if/where/foreach标签编写动态sql

6.1 if标签
  • test是条件表达式,可用ONGL表达式
<select id="findByUser" parameterType="user" resultType="user">
    select * from user where 1=1
    <if test="username!=null and !username.trim().equals('')">
        and username like #{username}
    </if>
    <if test="age!=null">
        and age>#{age}
    </if>
</select>
6.2 where标签
  • where标签会自动添加where关键字,并且删除where关键字相邻的and (等同where关键字替换了第一个and)
<!-- select * from user WHERE username like ? and age>?  -->
<select id="findByUser" parameterType="user" resultType="user">
    select * from user
    <where>
        <if test="username!=null and !username.trim().equals('')">
            and username like #{username}
        </if>
        <if test="age!=null">
            and age>#{age}
        </if>
    </where>
</select>
6.3 foreach
  • 定义个类,设置一个集合属性
package com.domain;
import java.util.List;
public class QueryObject {
    private List<Integer> ageList;
    public List<Integer> getAgeList() {
        return ageList;
    }

    public void setAgeList(List<Integer> ageList) {
        this.ageList = ageList;
    }
}
  • foreach使用
<!--  select * from USER where age in ( ? , ? , ? )  -->
 <select id="findByAge" resultType="user">
      select * from USER where age in
      <!-- collection的ageList对应QueryObject类的ageList,不用加#{} -->
      <!-- item表示遍历时每个对象的别名 -->
      <!-- open表示遍历前的前置字符,close表示遍历后的后置字符 -->
      <!-- separator表示集合每个元素用指定分隔符进行隔开 -->
      <foreach collection="ageList" item="age" open="(" close=")" separator=",">
          #{age}
      </foreach>
  </select>
  • 测试
List<Integer> ageList=new ArrayList<Integer>();
ageList.add(20);
ageList.add(12);
ageList.add(30);
QueryObject queryObject = new QueryObject();
queryObject.setAgeList(ageList);

List<User> list = userDao.findByAge(queryObject);
for (User u : list) {
    System.out.println(u);
}

7. mybatis集成PageHelper分页插件

7.1 引入PageHelper依赖
<!-- 引入分页插件依赖 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.2</version>
</dependency>
7.2 在mybatis主配置文件中添加PageHelper插件
  • 注意plugins标签在mybatis主配置中的位置顺序,参考上面5.1
<!-- 注意plugins的位置与顺序 -->
<plugins>
    <plugin interceptor	="com.github.pagehelper.PageInterceptor">
        <!-- 这里可以设置多个属性和值 -->
        <property name="reasonable" value="true"></property>
    </plugin>
</plugins>
7.3 PageHelper与PageInfo的方法使用
// PageHelper.startPage()方法必须在调用Dao方法前使用才能成功分页
// 第一个参数是当前页码,第二个参数是每页显示的记录数
PageHelper.startPage(2,2);
List<User> userList = userDao.findAll();
for (User user : userList) {
    System.out.println(user);
}

// 创建PageInfo对象并把查询结果集合数据存放进去
PageInfo<User> pageInfo=new PageInfo<User>(userList);
System.out.println("总记录数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示的记录数:"+pageInfo.getPageSize());
System.out.println("获取上一页页码:"+pageInfo.getPrePage());
System.out.println("获取下一页页码:"+pageInfo.getNextPage());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
System.out.println("是否还有上一页:"+pageInfo.isHasPreviousPage());
System.out.println("是否还有下一页:"+pageInfo.isHasNextPage());

// 从PageInfo中获取对象集合数据
List<User> list = pageInfo.getList();

7.4 SpringBoot使用PageHelper

        <!-- pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值