使用代理对象的方式实现CRUD操作
select
- select标签是mybatis中常用的查询标签
- select中有很多属性可以详细配置每一条SQL语句
- id属性:标识是我们接口中的那个方法。接口中的方法名与映射文件中的SQL语句id一一对应
- parameterType属性:用于指定传入的参数类型
- resultType属性:用于指定结果集的类型
- ......
需求:根据id查询用户
1、在UserDao中添加对应方法
/**
* 根据用户id查询用户
* @param userId 要查询的用户id
* @return 如果存在返回该用户,不存在则返回null
*/
User findById(Integer userId);
2、在UserDao.xml中添加select语句
<!--根据id查询用户(记住这里有返回值类型,要告知程序返回值类型是什么)-->
<select id="findById" resultType="com.lng.pojo.User">
select * from user where id = #{id};
</select>
3、在测试类中测试
这里和下面就不测试了,就是获取SqlSession对象来进行操作
查询使用聚合函数
1、在UserDao中添加对应方法
/**
* 查询总用户数
* @return
*/
int findTotal();
2、在UserDao.xml中添加对应的语句
<!--查询总用户数-->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
有多个查询条件(可能是同一个对象的,也可能不是同一个对象的)
例如根据用户名和地址查询用户
思路一:直接在方法中传递参数
1、在接口方法的参数前加@Param属性
2、Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
//在UserDao接口中添加如下方法
User findByAddAndName(@Param("username") String username, @Param("address") String address);
//在UserDao.xml中添加如下语句
<select id="findByAddAndName" resultType="com.lng.pojo.User">
select * from user where username = #{username} and address = #{address};
</select>
思路二:使用Map
1、在接口方法中,参数直接传递Map
User findByAddAndName(Map<String, Object> map);
<select id="findByIdAndName" resultType="com.lng.pojo.User" parameterType="map" >
select * from user where address = #{address} and username = #{username};
</select>
思路三:自定义一个查询类
其实这种方式和思路二是一个意思,就是将我们要查询的条件封装进一个类中,然后当成参数给传递过去
总结:如果参数较多的情况下建议使用Map或自定义实现类的方式,反之则使用直接传递参数的方式
注意事项
在使用增、删、改操作需要提交事务
一开始执行的时候就将自动提交事务给关闭了,所以要我们手动提交事务,使用sqlSession.commit()提交
insert
我们使用insert标签进行插入操作,他的配置和select差不多
给数据库增加一个用户
1、在UserDao接口中添加对应方法
/**
* 保存方法
* @param user
*/
void saveUser(User user);
2、在UserDao.xml中添加对应语句
<!--保存用户-->
<insert id="saveUser" parameterType="com.lng.pojo.User">
<!--配置插入操作后,获取插入数据的id,会自动填充至我们的User对象中-->
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id();
</selectKey>
insert into user (username, birthday, sex, address) values (#{username}, #{birthday}, #{sex}, #{address});
</insert>
update
使用update标签进行用户的更新
修改用户信息
1、编写接口方法
/**
* 更新操作
* @param user
*/
void updateUser(User user);
2、编写对应的配置文件SQL
<!--更新用户-->
<update id="updateUser" parameterType="com.lng.pojo.User">
update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address}
where id = #{id};
</update>
delete
可以使用delete标签进行删除操作。
删除用户
1、编写对应接口方法
/**
* 根据id删除用户
* @param userId 需要被删除的用户的id号
*/
void deleteUser(Integer userId);
2、编写对应配置文件的SQL
<!--删除用户-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id}; <!--如果参数是基本数据类型及其包装类,那么里面的占位符名随便写-->
</delete>
模糊查询
在java代码中添加sql通配符(常用)
/**
* 根据名称模糊查询用户名称
* @param username
* @return
*/
List<User> findByName(String username);
List<User> users = mapper.findByName("%王%");
<!--对应配置文件的写法-->
<!--根据名称模糊查询的语法-->
<select id="findByName" resultType="com.lng.pojo.User" parameterType="java.lang.String">
select * from user where username like #{username};<!--这种方式使用的是占位符的方式,所以在传递参数的时候要直接传递完整的模糊语句-->
</select>
- 执行的SQL
在sql语句中拼接通配符,会引起SQL注入等问题
/**
* 根据名称模糊查询用户名称
* @param username
* @return
*/
List<User> findByName(String username);
List<User> users = mapper.findByName("王");
<!--在对应中配置文件中编写-->
<!--根据名称模糊查询的语法-->
<select id="findByName" resultType="com.lng.pojo.User" parameterType="java.lang.String">
<!-- select * from user where username like '%${value}%'; 这种方式了解就行了,基本不会使用,这种方式不是用预处理SQL的方式-->
</select>
- 执行的SQL
配置解析
核心配置文件
- SqlMapConfig.xml核心配置文件
- Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息
- 能配置的内容如下:
environments元素
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
- 配置Mybatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认的运行环境(通过default指定)
- 子元素节点:environment
- dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源
- 数据源(dataSource)是必须配置的
- 有三种内建的数据源类型:type="[UNPOOLED|POOLED|JNDI]")
- unpooled:这个数据源的实现只是每次被请求是打开和关闭连接(没有使用数据库连接池技术)
- pooled:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来,这是一种使得并发Web应用快速响应请求的流行处理方式
- jndi:这个数据源的实现是为了能在如Spring或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文引用。
- 数据源也有很多第三方的实现:比如DBCP、c3p0、druid等等...
- 子元素节点:transactionManager-[事务管理器]:
<!-- 语法 -->
<transactionManager type="[ JDBC | MANAGED ]"/>
mappers元素
mappers
- 映射器:定义映射SQL语句文件的位置
- 既然Mybatis的行为其他元素已经配置完了,我们先就要定义SQL映射语句。但是首先我们需要告诉Mybatis到哪里去找到这些语句。Java在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉Mybatis到哪里去找映射文件。你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括file:///的URL),或类名和报名等。映射器是Mybatis中最核心的组件之一,在Mybatis3之前,只支持xml映射器,即:所有的SQL语句都必须在xml文件中配置。而从Mybatis3开始,还支持接口映射器,这种映射器方式允许Java代码的方式注解定义SQL语句,非常简洁。
引入资源的方式
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!--
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!--
将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
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="com.kuang.mapper.UserMapper">
</mapper>
- namespace中文意思:名称空间,作用如下
- namespace的命名必须跟某个接口的同名
- 接口中的方法与映射文件中SQL语句id应该一一对应
- namespace和子元素的id联合保证唯一性,区别不同的mapper
- 绑定DAO接口
- namespace命名规则:包名+类名
Properties优化
数据库这些属性都是可外部配置且可动态替换的,既可以在典型的Java属性文件中配置,亦可通过properties元素的子元素来传递。
1、在资源目录下新建一个JdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=123456
2、将文件导入properties配置文件
<configuration>
<!--导入properties文件-->
<properties resource="JdbcConfig.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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="mapper/UserMapper.xml"/>
</mappers>
</configuration>
typeAliases优化
类型别名视为Java类型设置一个短的名。他只和XML配置有关,存在的意义仅在于用来减少全类名书写的冗余
<!--使用typeAliases用于配置别名。-->
<typeAliases>
<!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就不再区分大小写
(不再区分大小写的的意思是下面引用别名的时候可以是user, USER, UsEr等都是可以的)
-->
<typeAlias type="com.lng.pojo.User" alias="user"/>
</typeAliases>
也可以指定一个包名,Mybatis会在包名下面搜索需要的JavaBean,如:
<!--使用typeAliases用于配置别名。-->
<typeAliases>
<!--用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不在区分大小写-->
<package name="com.lng.pojo"/>
</typeAliases>
若有注解,则别名为其注解值,如:
@Alias("user")
public class User {
...
}
注意:基本数据类型及其包装类和一些常用的类,Mybatis在加载的时候已经把常用的数据类型注册了别名
其他配置
设置
- 设置(settings)相关
- 懒加载
- 日志实现
- 缓存开启
- 一个完整的settings元素的实例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
类型处理器
- 无论是Mybatis在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式实现Java类型和JDBC类型的互相转化
- 可以自己重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型【了解即可】
对象工厂
- Mybatis每次创建结果对象的新实例时,他都会使用一个对象工厂(ObjectFactory)实例来完成
- 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过有参构造方法来实例化
- 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工程来实现【了解即可】