Mybatis学习02:使用xml进行Mybatis开发

本文详细介绍MyBatis中XML配置文件的使用方法,包括CRUD操作、输入输出参数映射、动态SQL语句及MyBatis配置文件的结构解析。

使用xml配置sql语句

CRUD的sql语句

查询操作

在持久层xml配置文件中使用<select>标签配置查询操作的sql语句.

java/cn/maoritian/dao/IUserDao.java中声明查询方法如下:

// 根据id查询用户信息
User findById(Integer userId);

resources/cn/maoritian/dao/IUserDao.xml中配置对应的sql语句如下:

<!-- 根据id查询用户信息 -->
<select id="findById" parameterType="java.lang.Integer" resultType="cn.maoritian.domain.User">
	select * from user where id = #{userId};
</select>

其中sql语句的占位符可以使用#{}${}表示,其区别如下:

  • #{}最后会编译成PreparedStatement对象的?占位符,花括号内为接收的方法参数,支持ONGL语句,即可以通过对象.属性调用pojo对象的对象.get属性()方法.

    通过#{}解析的占位符在进行变量替换时,会带上单引号',可以有效防止sql注入,应优先使用这种方式.

  • ${}表示拼接sql串,将占位符表示的内容直接拼接进sql语句.有可能发生sql注入漏洞.

    单这种表示方式也有其使用场景,因为#{}方式进行变量替换时,会带上单引号',因此表示sql语句中非参数部分,如表名和数据库列名时,只能使用${}.此时通过白名单的形式过滤花括号中的内容.

select * from ${tableName} where username = #{username} order by ${columnName}
-- sql注入隐患: 若tablename为" users; delete users; --"时,上面sql语句将会被解析为
select * from users; delete users; -- where username = #{username} order by ${columnName}

增加操作

在持久层xml配置文件中使用<insert>标签配置查询操作的sql语句.

java/cn/maoritian/dao/IUserDao.java中声明增加方法如下:

// 保存用户
void saveUser(User user);

resources/cn/maoritian/dao/IUserDao.xml中配置对应的sql语句如下:

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.maoritian.domain.User">
	<!-- 配置插入操作后,获取插入数据的id -->
	<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
		select last_insert_id();
	</selectKey>
	insert into users(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday});
</insert>

因为传入的是pojo对象,因此#{}占位符自动解析为其属性.

其中<selectKey>标签内调用sql语句select last_insert_id()可以返回上次操作的主键,并将其封装回原pojo对象.

@Test
public void testSave() {
    User user = new User(0, "姓名", "地区", "男", new Date());
    
    System.out.println("保存操作之前:" + user);
    userDao.saveUser(user);		// 执行保存方法
    System.out.println("保存操作之后:" + user);
}

可以看到,执行saveUser()方法之后,数据库中对应记录的主键被存进user对象的id字段.

更新操作

在持久层xml配置文件中使用<update>标签配置更新操作的sql语句.

java/cn/maoritian/dao/IUserDao.java中声明查询方法如下:

// 更新用户
void updateUser(User user);

resources/cn/maoritian/dao/IUserDao.xml中配置对应的sql语句如下:

<!-- 更新用户 -->
<update id="updateUser" parameterType="cn.maoritian.domain.User">
    update users set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
</update>

删除操作

在持久层xml配置文件中使用<delete>标签配置删除操作的sql语句.

java/cn/maoritian/dao/IUserDao.java中声明查询方法如下:

// 删除用户
void deleteUser(Integer userId);

resources/cn/maoritian/dao/IUserDao.xml中配置对应的sql语句如下:

<!-- 删除用户-->
<delete id="deleteUser" parameterType="java.lang.Integer">
	delete from users where id = #{userId};
</delete>

输入输出参数的映射

输入参数的映射

在配置CRUD语句时,我们在parameterType属性中定义其参数类型名称

  • 对于基本类型,我们可以可以直接写类型名称,也可以使用包名.类名的方式,例如:

    对于字符串类型的参数,我们既可以写string,也可以写java.lang.String.

  • 对于我们自己定义的实体类,必须写其全类名.

在Mybatis中,对于常见的类型,已经为我们配好了别名如下:

在这里插入图片描述

输出参数的映射

原来我们执行查询时,在sql语句上使用resultType=全类名或其别名,将数据库中的记录封装到pojo类中,但这种方式要求pojo类中的属性名与数据库表中的字段名完全相同.我们可以在dao接口实现类的xml配置文件中使用<resultMap>标签配置pojo类属性名到数据库字段名的映射,语法如下:

<!-- 配置 pojo类属性名 到 数据库字段名 的映射 -->
<resultMap type="cn.maoritian.domian.User" id="userMap">
    <!-- 主键字段的对应 -->
	<id column="id" property="userId"/>
    <!-- 非主键字段的对应 -->
	<result column="username" property="userName"/>
	<result column="sex" property="userSex"/>
	<result column="address" property="userAddress"/>
	<result column="birthday" property="userBirthday"/>
</resultMap>

各标签的属性:

  • type为pojo类的全类名,id为该映射的唯一标志,通过sql语句的resultMap属性引用该id
  • column属性指定数据库表的字段名,property属性指定pojo类的属性名
<select id="findById" resultMap="userMap">
    select * from users where id = #{userId};
</select>

动态sql语句

if标签-执行判断

<if>标签可以进行简单的逻辑判断,示例如下:

  • DAO层接口方法如下

    List<User> findByCondition(User user);
    
  • 在mapper中定义其实现如下

    <select id="findByCondition" resultMap="cn.maoritian.domain.User" parameterType="cn.maoritian.domain.User">
        select * from users where 1=1
        <if test="userName != null">
            and username like #{userName}
        </if>
        <if test="userSex != null">
            and sex = #{userSex}
        </if>    
    </select>
    
  • 测试方法如下

    @Test
    public void testFindByCondiion() throws Exception {
        // 通过赋值给对象属性确定查询条件
        User user = new User();
        user.setUserName("%王%");   // 查询名字时使用模糊查询
        user.setUserSex("女");
        // 执行查询方法
        List<User> users = userDao.findByCondition(user);
        for (User u : users) {
            System.out.println(u);
        }
    }
    

where标签-为sql语句加上where限定符

上边例子中的sql语句加上了一个限定条件where 1=1,以防止我们传入的user对象为空,这种实现方式并不优雅.我们可以使用<where>标签,它可以根据我们传入的pojo对象判断是否加上where语句,示例如下:

<select id="findByCondition" resultMap="cn.maoritian.domain.User" parameterType="cn.maoritian.domain.User">
    select * from users
    <where>
        <if test="userName != null">
            and username like #{userName}
        </if>
        <if test="userSex != null">
            and sex = #{userSex}
        </if>    
    </where>
</select>

foreach标签-遍历集合

当我们想要执行范围查询时(如select * from users where id in (1,2,3,4,5);),要用到<foreach>标签.

  • DAO层接口方法如下:

    List<User> findInIds(List<Integer> ids);
    
  • 在mapper中定义其实现如下:

    <select id="findUserInIds" resultMap="cn.maoritian.domain.User" parameterType="list">
    	select * from users
    	<where>
    		<if test="ids!=null and ids.size()>0">
    			<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
    				#{uid}
    			</foreach>
    		</if>
    	</where>
    </select>
    

    <foreach>标签的属性如下:

    • collection: 代表被遍历的对象,支持ONGL语言(如paramObject.idList)
    • item: 代表每次循环拿到的对象

<foreach>标签更具体的使用方法参考这篇文章使用foreach实现mybatis查询

sql标签-抽取重复语句

每个方法的sql语句中,有大量重复的部分,可以使用<sql>标签声明sql语句,使用<include>标签引用其中内容.

<sql id="defaultUser">
	select * from users
</sql>

<select id="findByCondition" resultMap="cn.maoritian.domain.User" parameterType="cn.maoritian.domain.User">
	<include refid="defaultUser"/>
	<where>
		<if test="userName != null">
			and username like #{userName}
		</if>
		<if test="userSex != null">
			and sex = #{userSex}
		</if>    
	</where>
</select>

Mybatis配置文件SqlMapConfig.xml

一个完整的Mybatis配置文件SqlMapConfig.xml的结构和顺序如下:

-properties(属性)
	--property
-settings(全局配置参数)
	--setting
-typeAliases(类型别名)
	--typeAliase
	--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
	--environment(环境子属性对象)
		---transactionManager(事务管理)
		---dataSource(数据源)
-mappers(映射器)
	--mapper
	--package

Properties标签-配置JDBC连接参数

<properties>标签内可以配置JDBC参数,具体来说有两种方式配置

  1. 使用<property>标签直接配置

    <properties>
    	<property name="jdbc.driver" value="com.mysql.jdbc.Driver"></property>
    	<property name="jdbc.url" value="jdbc:mysql://localhost:3306/数据库名"></property>
    	<property name="jdbc.username" value="用户名"></property>
    	<property name="jdbc.password" value="密码"></property>
    </properties>
    
    <!-- 其他内容 -->
    
    <environments default="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>
    
  2. 使用<properties>标签的resource属性或URL属性

    <properties resource="jdbcConfig.properties" />
    
    <!-- 其他内容 -->
    
    <environments default="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>
    

    其中jdbcConfig.properties文件resources目录下,其内容如下:

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/数据库名
    jdbc.username=用户名
    jdbc.password=密码
    

typeAliases标签-为bean类起别名

<typeAliases>可以为bean类起别名. 通过type,parameterType,resultType等属性引用该实体类.

<typeAliases>标签内指定的别名不区分大小写

有两种方式配置别名

  1. 使用<typeAlias>标签为单个bean类起别名:

    <typeAliases>
    	<typeAlias type="cn.maoritian.domain.User" alias="user"></typeAlias>
    </typeAliases>
    
  2. 通过<package>标签为整个包内的bean类起别名,其别名即为该类的直接类名,不区分大小写

    <typeAliases>
        <package name="cn.maoritian.domain"></package>
    </typeAliases>
    

配置别名之后,就可以在指定dao层方法sql语句时通过type,parameterType,resultType属性引用该实体类.

mappers映射器-指定dao层方法的具体实现

可以通过两种方式配置<mappers>

  1. 通过<mapper>标签为每一个dao层类配置具体实现

    <mappers>
        <mapper resource="cn/maoritian/dao/IUserDao.xml"></mapper>
        <mapper resource="cn/maoritian/dao/IAccountDao.xml"></mapper>
        <mapper resource="cn/maoritian/dao/IProductDao.xml"></mapper>
    </mappers>
    
  2. 通过<package>标签配置dao层类所在的包,相当于为其中每一个dao层类都配置了具体实现

    <typeAliases>
        <package name="cn.maoritian.domain"></package>
    </typeAliases>
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值