Mybatis3详解(六)----通过注解映射实现Mybatis实例
1、本章前言
我们都知道注解能够帮我们减少大量的代码和配置,基本上每个人都喜欢用注解进行配置,包括我自己,因为实在太方便了。但是Mybatis是一个特例,因为Mybatis使用注解的话,如果SQL复杂点会导致可读性极差,所以Mybatis一般都不推荐使用注解实现,推荐使用基于Mapper接口的xml版本实现。通过注解映射实现Mybatis实例我们暂时只需简单了解即可。
2、创建数据库
创建数据库(mybatis)和表(t_user),完成创建数据库和表的操作后如下图所示:
插入一些测试数据:
INSERT INTO `t_user` VALUES (1, '奥利给', '2002-04-28', 18, '男', '上海');
INSERT INTO `t_user` VALUES (2, '蔡徐坤', '2001-06-08', 18, '男', '北京');
INSERT INTO `t_user` VALUES (3, '马保国', '2004-11-12', 42, '男', '深圳');
INSERT INTO `t_user` VALUES (4, '十三姨', '1998-01-18', 18, '女', '大清');
3、创建Maven项目
在Eclipse或IDEA中创建一个Maven项目。
然后导入pom依赖,如下:
<dependencies>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- 日志处理 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
4、创建User实体
创建一个User实体类,这里省略了getter、setter和toString方法,需自己加上。
/**
* 用户实体类
*/
public class User {
private int userId;
private String userName;
private int userAge;
private Date userBirthday;
private String userSex;
private String userAddress;
//getter、setter、toString方法省略......
}
5、创建Mybatis全局配置文件
在resources目录中,创建Mybatis的全局配置文件mybatis-config.xml。代码如下:
注意:这里面配置了别名,扫描所有实体包,给实体类起个别名,别名就是小写字母的类名。
<?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>
<!--配置别名-->
<typeAliases>
<!-- 对包进行扫描,可以批量进行别名设置,设置别名的规则是:获取类名称,将其第一个字母变为小写 -->
<package name="com.thr.entity"/>
</typeAliases>
<!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境 -->
<environments default="development">
<!-- environment表示配置Mybatis的一个具体的环境 -->
<!-- id属性必须和上面的default一致 -->
<environment id="development">
<!--配置Mybatis的内置的事务管理器-->
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
6、编写Mapper接口
Mapper接口代码如下(命名不一定是XxxMapper,也可以是XxxDao等等),当使用了注解的方式就不在需要XXXMapper.xml文件了。
/**
* UserMapper接口,使用注解配置
*/
public interface UserMapper {
//查询所有用户
@Select("select * from t_user")
@Results(id = "userMap",value = {
@Result(property = "userId", column = "id",id = true),
@Result(property = "userName", column = "username"),
@Result(property = "userAge", column = "age"),
@Result(property = "userBirthday", column = "birthday"),
@Result(property = "userSex", column = "sex"),
@Result(property = "userAddress", column = "address"),
})
List<User> selectAllUser();
//根据id查询用户
@Select("select * from t_user where id = #{id}")
@ResultMap("userMap")
User selectUserById(Integer id);
//根据用户名和地址模糊查询用户列表
@Select("select * from t_user where username like concat('%',#{userName},'%') and address like concat('%',#{userAddress},'%')")
@ResultMap("userMap")
List<User> selectUserByNameAndAddress(@Param("userName") String userName,@Param("userAddress") String userAddress);
//添加用户
@Insert("insert into t_user(username,age,birthday,sex,address) values " +
"(#{userName},#{userAge},#{userBirthday},#{userSex},#{userAddress});")
Integer insertUser(User user);
//修改用户信息
@Update("update t_user set username = #{userName},age = #{userAge}, birthday = #{userBirthday}," +
"sex = #{userSex},address = #{userAddress} where id = #{userId}")
Integer updateUser(User user);
//删除用户
@Delete("delete from t_user where id = #{id}")
Integer deleteUser(Integer id);
}
mybatis中一些常用注解介绍:
①、@Select()、@Insert()、@Update()、@Delete()
:基本增删改查注解
②、@Results()
:结果映射的列表,相当于resultMap标签,id表示结果映射的名字,value表示的是 @Result 的数组。注意:@Results需要和@Select配合使用,单独的@Results不会被识别。
③、@Result()
:在列和属性或字段之间的单独结果映射。属性有:id,column, property, javaType ,jdbcType ,typeHandler, one,many。
属性名 | 描述 |
---|---|
id | 是一个布尔值,表示是否为主键 |
column | 数据库字段名或者其别名(这个别名是数据库起的,如 username as name) |
property | 实体类属性名 |
javaType | 映射java的类型 |
jdbcType | 映射数据库类型 |
typeHandler | 数据库与Java类型匹配处理器(可以参考前面的TypeHandler部分) |
one | 属性是单独的联系,用来一对一操作, 和 <association> 相似 |
many | 属性是对集合而言的,用来一对多操作 , 和 <collection>相似 |
④、@One
:一对一注解。select属性必须是已映射语句的完全限定名(也就是接口的方法),它可以加载合适类型的实例。 fetchType会覆盖全局的配置参数lazyLoadingEnabled。
@Result(property = "property", column = "column", javaType = User.class,one=@One(select = "com.thr.mapper.XxxMapper.Method_Name",fetchType = FetchType.DEFAULT)),
⑤、@Many
:一对多注解。select属性必须是已映射语句的完全限定名(也就是接口的方法),它可以加载合适类型的实例的集合,fetchType会覆盖全局的配置参数lazyLoadingEnabled。
@Result(property = "property", column = "column", javaType = User.class,many=@Many(select = "com.thr.mapper.XxxMapper.Method_Name",fetchType = FetchType.DEFAULT)),
⑥、@ResultMap()
:用来引用定义的结果映射的列表(@Results)。这使得注解的@Select可以复用那些定义在ResultMap中的内容。如果同一@Select注解中还存在@Results或者@ConstructorArgs,那么这两个注解将被此注解覆盖。
⑦、@Param()
:如果Mapper接口中的方法需要多个参数,,这个注解可以被应用于映射器的方法参数来给每个参数一个名字。否则,多参数将会以它们的顺序位置来被命名 (不包括任何 RowBounds 参数) 比如:#{param1} , #{param2} 等(这是默认的)。使用 @Param("userName"),SQL参数就应该被命名为 #{userName}。
7、导入日志文件
导入日志文件,在resources目录中创建log4j.xml文件(这种方式打印的数据更加清晰),并且导入如下配置(如果log报错则以管理员的方式启动Eclipse或IDEA)。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
8、编写测试代码
最后创建一个MybatisTest的测试类,其源代码如下所示:
/**
* Mybatis的测试
*/
public class MybatisTest {
//定义 SqlSession
private SqlSession sqlSession = null;
//定义 UserMapper对象
private UserMapper mapper = null;
@Before//在测试方法执行之前执行
public void getSqlSession(){
//1、加载 mybatis 全局配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3、根据 sqlSessionFactory 产生 session
sqlSession = sqlSessionFactory.openSession();
//4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
mapper = sqlSession.getMapper(UserMapper.class);
}
@After//在测试方法执行完成之后执行
public void destroy() throws IOException {
sqlSession.commit();
sqlSession.close();
}
//查询所有用户数据
@Test
public void testSelectAllUser(){
List<User> listUser = mapper.selectAllUser();
for (User user : listUser) {
System.out.println(user);
}
}
//根据Id查询一个用户数据
@Test
public void testSelectUserById(){
User user = mapper.selectUserById(1);
System.out.println(user);
}
//模糊查询:根据username和address字段
@Test
public void testSelectUserByName(){
List<User> userList = mapper.selectUserByNameAndAddress("三","大");
for(User user : userList){
System.out.println(user);
}
}
//添加一个用户数据
@Test
public void testInsertUser(){
User user = new User();
user.setUserName("法外狂徒张三");
user.setUserAge(42);
user.setUserBirthday(new Date());
user.setUserSex("男");
user.setUserAddress("中国监狱");
Integer i = mapper.insertUser(user);
System.out.println(i);
System.out.println( (i>0)? "添加成功!":"添加失败!");
}
//根据Id修改用户数据
@Test
public void testUpdateUser(){
//如果设置的 id不存在,那么数据库没有数据更改
User user = new User();
user.setUserId(3);
user.setUserName("张红");
user.setUserAge(42);
user.setUserBirthday(new Date());
user.setUserSex("女");
user.setUserAddress("新疆");
Integer i = mapper.updateUser(user);
System.out.println( (i>0)? "修改成功!":"修改失败!");
}
//根据Id删除用户数据
@Test
public void testDeleteUser(){
Integer i = mapper.deleteUser(3);
System.out.println( (i>0)? "删除成功!":"删除失败!");
}