Mybatis系列文章
- Mybatis学习笔记 - 01
- Mybatis学习笔记 - 02
- Mybatis学习笔记 - 03
- Mybatis学习笔记 - 04
saveUser()
方法public interface UserMapper {
/**
* 查询所有用户
*
* @return
*/
List<User> listAllUsers();
/**
* 添加用户
* @param user
* @return 成功返回1,失败返回0
*/
int saveUser(User user);
}
UserMapper.xml
中配置添加操作
<mapper namespace="cn.ykf.mapper.UserMapper">
<select id="listAllUsers" resultType="cn.ykf.pojo.User">
SELECT * FROM user
select>
<insert id="saveUser" parameterType="cn.ykf.pojo.User">
INSERT INTO user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
insert>
mapper>
parameterType
表示将会传入这条语句的参数类的完全限定名或别名。- 其中的参数符号
#{username}
,#{birthday}
,#{birthday}
,#{sex}
,#{address}
必须和User类的每个属性名一一对应,不可以乱写。
- 属性名是实体类的
getXxx()/setXxx()
中Xxx
部份,大多数情况下就是成员变量名,也有少数情况不是成员变量名,也就是说成员变量和属性不能等同。- 关于配置文件的相关说明,可以查看官网文档:Mybatis的XML映射文件
public class MybatisTest {
private InputStream is;
private SqlSession sqlSession;
private UserMapper mapper;
/**
* 测试之前执行,用于初始化
*/
@Before
public void init() throws Exception {
// 1. 读取配置文件
is = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 3. 获取SqlSession对象
sqlSession = factory.openSession();
// 4. 使用SqlSession创建Mapper的代理对象
mapper = sqlSession.getMapper(UserMapper.class);
}
/**
* 测试结束执行,用于提交事务和释放资源
*/
@After
public void destroy() throws Exception {
// 6. 提交事务
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
is.close();
}
/**
* 测试添加用户
*/
@Test
public void testSaveUser() {
User user = new User();
user.setUsername("鱼开饭");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("广东");
// 调用mapper完成添加
int count = mapper.saveUser(user);
System.out.println("添加条数为 : " + count);
}
}
removeUserById()
方法/**
* 根据id删除用户
*
* @param userId
* @return 成功返回1,失败返回0
*/
int removeUserById(Integer userId);
UserMapper.xml
中配置删除操作
<delete id="removeUserById" parameterType="java.lang.Integer">
DELETE FROM user WHERE id = #{uid}
delete>
- 这里有两点需要注意一下!
- 第一点,如果参数是基本类型或者基本类型的包装类,且只有一个参数,那么参数符号可以随便写 。也就是说,虽然 Mapper 接口中的方法声明为
int removeUserById(Integer userId)
,但是映射文件中既可以写#{userId}
,也可以写#{aaaa}
。- 第二点,
parameterType
写int
、INT
、INTEGER
、integer
、java.lang.Integer
都可以。原因可以看 6.2 typeAliases 标签
/**
* 测试删除用户
*/
@Test
public void testremoveUserById(){
// 这里传的id为自己数据库中存在的id值
int count = mapper.removeUserById(50);
System.out.println("删除条数为 : " + count);
}
updateUser()
方法/**
* 修改用户
* @param user
* @return 成功返回1,失败返回0
*/
int updateUser(User user);
UserMapper.xml
中配置修改操作
<update id="updateUser" parameterType="cn.ykf.pojo.User">
UPDATE user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
update>
/**
* 测试修改用户
*/
@Test
public void testUpdateUser() {
// 因为还没有编写根据id查询用户,所以模拟数据
User user = new User();
user.setUsername("update");
user.setAddress("test");
user.setSex("女");
user.setBirthday(new Date());
// id 为自己数据库中存在的值
user.setId(49);
// 执行修改
int count = mapper.updateUser(user);
System.out.println("修改条数为 : " + count);
}
UserMapper
中添加方法/**
* 根据id查询单个用户
* @param userId
* @return
*/
User getUserById(Integer userId);
<select id="getUserById" parameterType="java.lang.Integer" resultType="cn.ykf.pojo.User">
SELECT * FROM user WHERE id = #{uid}
select>
/**
* 测试查询单个用户
*/
@Test
public void testGetUserById() {
// 确保id存在,否则返回null
User user = mapper.getUserById(48);
System.out.println(user);
}
UserMapper
中添加方法/**
* 根据姓名模糊查询多个用户
*
* @param username
* @return
*/
List<User> listUsersByName(String username);
<select id="listUsersByName" parameterType="java.lang.String" resultType="cn.ykf.pojo.User">
SELECT * FROM user WHERE username LIKE #{name}
select>
- 虽然
UserMapper
中方法的返回值为List
,但是映射文件中resultType
写User
就行。因为如果有多条记录的话,Mybatis 会自动帮我们封装成一个 List 集合。- 这里的
parameterType
也可以直接写String
。- 参数符号可以随便写。
/**
* 测试模糊查询
*/
@Test
public void testListUsersByName() {
List<User> users = mapper.listUsersByName("%王%");
// 使用 Stream 流 + 方法引用,需要至少jdk8
users.forEach(System.out::println);
}
- 如果出现了
There is no getter of 'name' in java.lang.string
的错误,请参考链接:mybatis中传入String类型参数的问题- 由于映射文件中的 SQL 语句并没有对参数进行模糊查询处理,所以在调用方法的时候我们必须手动为查询的关键字进行
%
拼接,这样很不方便。如果想调用方法查询时,只传入查询的关键字,那么可以采用以下方法 :
- 在 SQL 语句中,使用 MySQL 默认提供的函数
concat()
进行拼接SELECT * FROM user WHERE username LIKE concat('%',#{name},'%');
- 在 SQL 语句中手动进行拼接
SELECT * FROM user WHERE username LIKE "%"#{name}"%";
UserMapper
中添加方法/**
* 查询用户总数
*
* @return
*/
int countUser();
<select id="countUser" resultType="int">
SELECT count(id) FROM user
select>
/**
* 测试查询用户总数
*/
@Test
public void testCountUser() {
int count = mapper.countUser();
System.out.println("用户总记录数为 : " + count);
}
标签,见代码
<insert id="saveUser" parameterType="cn.ykf.pojo.User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
selectKey>
INSERT INTO user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
insert>
keyProperty
表示 selectKey 语句结果应该被设置的目标属性(对应实体类)。keyColumn
表示匹配属性的返回结果集中的列名称(对应数据库结果集)。order
可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先生成主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后再执行 selectKey 中的语句。
/**
* 测试添加用户,并获取 id 的返回值
*/
@Test
public void testSaveUser() {
User user = new User();
user.setUsername("鱼开饭");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("广东");
System.out.println("添加前 : " + user);
// 调用mapper完成添加
int count = mapper.saveUser(user);
System.out.println("添加条数为 : " + count);
System.out.println("添加后 : " + user);
}
Object Graphic Navigation Language
,即对象图导航语言QueryVo
类来封装查询条件/**
* 用于封装查询条件
*
* @author yukaifan
* @ClassName QueryVo
* @date 2020/2/1 11:04
*/
public class QueryVo implements Serializable {
private User user;
// 如果还有其他的查询条件,就可以一并封装进来
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
/**
* 根据查询条件模糊查询用户
*
* @param vo
* @return
*/
List<User> listUsersByVo(QueryVo vo);
<select id="listUsersByVo" parameterType="cn.ykf.pojo.QueryVo" resultType="cn.ykf.pojo.User">
SELECT * FROM user WHERE username LIKE CONCAT('%',#{user.username},'%')
select>
/**
* 测试根据Vo查询
*/
@Test
public void testListUsersByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("王");
vo.setUser(user);
List<User> users = mapper.listUsersByVo(vo);
users.forEach(System.out::println);
}
public class User implements Serializable {
// 此时实体类属性与数据库表的列表已经不一致了
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
// 此处不展示 getter()/setter()...
// 此处不展示 toString()...
}
原本应该所有的属性都为 null ,但是由于在 Windows 环境下 MySQL 不区分大小,所以
userName
等同username
,不过要注意在 Linux 环境下 MySQL 严格区别大小写。
<select id="listAllUsers" resultType="cn.ykf.pojo.User">
SELECT id AS userId, username AS userName, birthday AS userBirthday, sex AS userSex, address AS userAddress FROM user
select>
<mapper namespace="cn.ykf.mapper.UserMapper">
<resultMap id="userMap" type="cn.ykf.pojo.User">
<id property="userId" column="id" />
<result property="userName" column="username"/>
<result property="userBirthday" column="birthday"/>
<result property="userAddress" column="address"/>
<result property="userSex" column="sex"/>
resultMap>
<select id="listAllUsers" resultMap="userMap">
SELECT * FROM user
select>
mapper>
properties
标签username、password
等属性就可以复用,提高开发效率。
<configuration>
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
<mappers>
<mapper resource="UserMapper.xml"/>
mappers>
configuration>
resources
属性引入外部配置文件(常用)编写配置文件
jdbcConfig.properties
。配置文件名没有限制,但是配置文件一定要放在类路径下
# 键为 jdbc.xxx 可以自行修改
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis
jdbc.username=root
jdbc.password=123456
修改 Mybatis 配置文件
<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>
url
属性引入外部配置文件该方法的外部文件可以放在任意位置,但是路径写法必须按照 Url 的方式,写起来比较麻烦,推荐第二种方法
<properties url="file:///D:/document/IdeaProjects/java_web_ssm/my_mybatis/src/main/resources/jdbcConfig.properties"/>
- URL:Uniform Resouce LOcator,即统一资源定位符。它可以唯一标识一个资源的位置,由四部分组成:协议、主机、端口、路径。
- 例如:http://localhost:8080/mybatisserver/demo1,其中
http
为协议,localhost
为主机,8080
为端口号,/mybatisserver/demo1
为uri(路径)- URI:Uniform Resource Identifier,即统一资源标识符。它是在应用中可以唯一定位一个资源的。
typeAliases
标签resultType
这个属性可以写 int、INT
等,就是因为 Mybatis 给这些类型起了别名。Mybatis 内置的别名如表格所示:别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
typeAliases
标签。用法如下:<configuration>
<typeAliases>
<typeAlias type="cn.ykf.pojo.User" alias="user"/>
typeAliases>
configuration>
typeAlias
子标签用于配置别名。其中type
属性用于指定要配置的类的全限定类名(该类只能是某个domain实体类),alias
属性指定别名。一旦指定了别名,那么别名就不再区分大小写。- 也就是说,此时我们可以在映射文件中这样写
resultType="user"
,也可以写resultType="USER"
。
package
标签。<typeAliases>
<package name="cn.ykf.pojo"/>
typeAliases>
package
标签指定要配置别名的包,当指定之后,该包下的所有实体类都会注册别名,并且别名就是类名,不再区分大小写
package
标签还可以将某个包内的映射器接口实现全部注册为映射器,如下所示
<mappers>
<package name="cn.ykf.mapper"/>
mappers>