MyBatis 学习1
简介
MyBatis 基于 java 的持久层框架,它内部封装了 JDBC,使开发者只需要关注 SQL 语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。 MyBatis 通过 XML 或注解的方式将要执行的各种 statement 配置起来,并通过 Java 对象和 statement 中 SQL 的动态参数进行映射生成最终执行的 SQL 语句,最后由 MyBatis 框架执行 SQL 并将结果映射为 Java 对象并返回。
入门案例
创建数据库、表,然后再随意写入几条数据:
CREATE DATABASE `mybatis_demo`;
USE mybatis_demo;
CREATE TABLE `t_user`(
`id` INT(8) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(20) NOT NULL,
`birthday` DATETIME DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
这里只是简单演示所以创建个普通java项目即可:
pom.xml 导入相关依赖(主要是 MyBatis 和 MySQL):
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
User 类
public class User implements Serializable {
//和数据库里的字段名一样
private int id;
private String username;
private Date birthday;
//省略 getter、setter、toString 方法
}
IUserDao 接口
public interface IUserDao {
//查询所有
List<User> findAll();
}
resources文件夹里创建 SqlMapConfig.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">
<!--mybatis配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置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/mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,即每个dao独立的配置文件-->
<mappers>
<mapper resource="com/rgb3/dao/IUserDao.xml"/>
</mappers>
</configuration>
IUserDao.xml 映射文件
<?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.rgb3.dao.IUserDao">
<!--配置查询所有-->
<!--id值跟接口里面的方法名一样-->
<select id="findAll" resultType="com.rgb3.domain.User">
select * from t_user;
</select>
</mapper>
MyBatisTest 测试类
public class MyBatisTest {
public static void main(String[] args) throws Exception {
//读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//用代理对象执行方法
List<User> users = userDao.findAll();
for (User user :users ) {
System.out.println(user);
}
}
}
目录
启动测试
注意:
- MyBatis 的xml 映射文件位置要和 dao java接口的包结构一样。
- xml 映射文件的 mapper 标签 namespace 属性值为 dao 接口的全限定类名。
- xml 映射文件的操作配置(如CRUD操作),id 属性值要和 dao 接口的方法名一样。
上面就是用 XML 的方式使用,还可以用注解的方式使用。
-
要把之前的 IUserDao.xml 移除,在 dao 接口的方法上,查询就用 @Select 注解。
public interface IUserDao { //查询所有 @Select("select * from t_user") List<User> findAll(); }
-
在MyBatis 的配置文件 SqlMapConfig.xml 文件中进行 mapper 配置时,就不用 resouce 属性指定了,用 class 属性指定 java 接口
<mappers> <!-- <mapper resource="com/rgb3/dao/IUserDao.xml"/>--> <mapper class="com.rgb3.dao.IUserDao"/> </mappers>效果一样
启动效果一样的。
MyBatis 支持使用 XML 配置、注解配置、和自己写 dao 实现类的方式,在实际开发中为了简便,一般都是不写 dao 实现类的方式。
简易CRUD操作
IUserDao 接口
public interface IUserDao {
//查询所有
List<User> findAll();
//根据id查询
User findById(int id);
//根据名称模糊查询
List<User> findByName(String name);
//使用聚合函数 count(),查询数据总数
int findTotal();
//保存用户
void saveUser(User user);
//修改用户
void updateUser(User user);
//删除用户
void deleteUser(int id);
}
IUserDao.xml
<?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.rgb3.dao.IUserDao">
<!--查询所有-->
<!--id值跟接口里面的方法名一样-->
<select id="findAll" resultType="com.rgb3.domain.User">
select * from t_user;
</select>
<!--根据id查询-->
<select id="findById" parameterType="int" resultType="com.rgb3.domain.User">
select * from t_user where id=#{id}
</select>
<!--根据名称模糊查询-->
<select id="findByName" parameterType="String" resultType="com.rgb3.domain.User">
<!--有一种写法是 like %${value}%,这样java代码那边就不用加%了,但是这样是字符串拼接形式的,实际中一般不用,
用下面的占位符的形式使用就行了
-->
select * from t_user where username like #{username}
</select>
<!--使用聚合函数 count(),查询数据总数-->
<select id="findTotal" resultType="int">
select count(id) from t_user;
</select>
<!--保存用户-->
<insert id="saveUser" parameterType="com.rgb3.domain.User">
<!--
新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,
所以就相当于我们要在新增后将自动增长 auto_increment 的值返回
-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into t_user(username,birthday) values(#{username},#{birthday});
</insert>
<!--修改用户-->
<update id="updateUser" parameterType="com.rgb3.domain.User">
update t_user set username=#{username},birthday=#{birthday} where id=#{id};
</update>
<!--删除用户-->
<!--当方法参数只有1个时,where id = #{id} #{这里面的内容可以随便写}-->
<delete id="deleteUser" parameterType="int">
delete from t_user where id = #{id};
</delete>
</mapper>
SqlMapConfig.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">
<!--mybatis主配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置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/mybatis_demo?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,即每个dao独立的配置文件-->
<mappers>
<!--xml形式-->
<mapper resource="com/rgb3/dao/IUserDao.xml"/>
<!--注解形式-->
<!--<mapper class="com.rgb3.dao.IUserDao"/>-->
</mappers>
</configuration>
MyBatisTest 测试类,初始方法和结束方法
public class MyBatisTest {
private InputStream in ;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Before//测试方式运行前运行
public void init() throws Exception {
//读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
factory = new SqlSessionFactoryBuilder().build(in);
//用工厂生产SqlSession对象
session = factory.openSession();
//用SqlSession创建Dao接口的代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//测试方法运行后运行
public void destroy() throws Exception{
//提交事务
session.commit(); //保存、修改、删除操作时,如果你没这步提交事务,是不能成功处理数据的
in.close();
session.close();
}
//...测试方法
}
数据库
查询全部
//查询全部
@Test
public void findAll(){
List<User> all = userDao.findAll();
for (User user:all){
System.out.println(user);
}
}
根据 id 查询
//根据id查询
@Test
public void findById(){
User user= userDao.findById(33);
System.out.println(user);
}
模糊查询
//模糊查询
@Test
public void findByName(){
List<User> all = userDao.findByName("%t%");//注意要自己加百分号%
for (User user:all){
System.out.println(user);
}
}
使用聚合函数
//使用聚合函数 count(),查询数据总数
@Test
public void findTotal(){
int total = userDao.findTotal();
System.out.println("数据总数:"+total);
}
保存用户
//保存用户
@Test
public void saveUser() {
User user = new User();
user.setUsername("小飞");
user.setBirthday(new Date());
System.out.println("id:"+user.getId());
userDao.saveUser(user);
System.out.println("新增用户后id:"+user.getId());//新增用户后,同时还要返回当前新增用户的 id 值
}
修改用户
//修改用户
@Test
public void updateUser(){
User user = new User();
user.setId(37);
user.setUsername("小兰");
user.setBirthday(new Date());
userDao.updateUser(user);
}
删除用户
//删除用户
@Test
public void deleteUser(){
userDao.deleteUser(37);
}
MyBatis 参数
parameterType 参数
取值可以是基本数据类型(如:int),引用类型(如String),实体类(如自定义的User类),实体类的包装类(就是User类外面再套一个类)
QueryVO 实体类的包装类
public class QueryVO implements Serializable {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
接口方法
List<User> findByQueryVO(QueryVO queryVO);
映射配置
<!--用实体类的包装类查询-->
<select id="findByQueryVO" resultType="com.rgb3.domain.User" parameterType="com.rgb3.domain.QueryVO">
select * from t_user where username like #{user.username};
</select>
测试方法
@Test
public void findByQueryOV(){
QueryVO queryVO = new QueryVO();
User user = new User();
user.setUsername("%t%");//注意要自己加百分号%
queryVO.setUser(user);
List<User> all = userDao.findByQueryVO(queryVO);
for (User u:all){
System.out.println(u);
}
}
resultType 结果类型
之前说实体类变量名要和数据表里的字段名要一样,实际上不一样也是可以的。
在实体类里变量名叫 userid ,数据表里 id,之前是这样:
<select id="findAll" resultType="com.rgb3.domain.User">
select * from t_user;
</select>
现在2个名字不一样了,可以使用别名:
<select id="findAll" resultType="com.rgb3.domain.User">
select id as userId from t_user;
</select>
提示:如果实体类里的变量名是 userName,数据表里叫 username,两者虽大小写不一样,但 MyBatis 还是能把他们映射起来的,因为 MySQL 在 Windows 系统中不区分大小写,但在 Linux 里就有区分。
<resultMap>
上面是使用别名的方法,还有一种方法就是用 <resultMap> 标签来表示实体类变量名和数据表里字段名的对应关系。
<!--配置查询结果的列名和实体类的属性名的对应关系-->
<resultMap id="userMap" type="com.rgb3.domain.User">
<!--主键字段的对应-->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<select id="findAll" resultType="com.rgb3.domain.User">
select * from t_user;
</select>
这里就不用 resultType 了,用 resultMap,如下:
<select id="findAll" resultMap="userMap">
select * from t_user;
</select>
测试成功
MyBatis 配置文件标签
<properties>
用于指定属性配置
方式1:
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis_demo?characterEncoding=utf-8"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
</properties>
方式2:
在类路径下创建一个 jdbcConfig.properties 文件
把配置属性放在里面
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_demo?characterEncoding=utf-8
jdbc.username =root
jdbc.password =root
在我们的 MyBatis 配置文件,SqlMapConfig.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">
<!--mybatis配置文件-->
<configuration>
<!--配置properties
resource 属性:指定配置文件的位置,按照类路径的写法来写,且必须存放在类路径下
也可以用 url 的形式写 如 url="file:///E:/javaEE-Projects/mybatisdemo/src/main/resources/jdbcConfig.properties"
-->
<properties resource="jdbcConfig.properties"></properties>
<!--配置环境-->
<environments default="mysql">
<!--配置mysql的环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<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>
<!--指定映射配置文件的位置,即每个dao独立的配置文件-->
<mappers>
<!--xml形式-->
<mapper resource="com/rgb3/dao/IUserDao.xml"/>
<!--注解形式-->
<!--<mapper class="com.rgb3.dao.IUserDao"/>-->
</mappers>
</configuration>
这一行
<properties resource="jdbcConfig.properties"></properties>
指定了在类路径下的 jdbcConfig.properties 属性文件。
这里
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
指定了属性文件里面的属性,用 ${} 指定。
<typeAliases> 指定别名
<typeAlias>
在 MyBatis 配置文件 SqlMapConfig.xml 里加上:
<!--配置别名,只能配置 domain 中类的别名-->
<typeAliases>
<!-- type 指定实体类的全限定类名,alias 属性指定别名,指定后别名不区分大小写。-->
<typeAlias type="com.rgb3.domain.User" alias="user"></typeAlias>
</typeAliases>
IUserDao.xml 里之前是这样的:
<!--根据id查询-->
<select id="findById" parameterType="int" resultType="com.rgb3.domain.User">
select * from t_user where id=#{id}
</select>
可以改为这样:
<!--根据id查询-->
<select id="findById" parameterType="int" resultType="user">
select * from t_user where id=#{id}
</select>
之前因为实体类属性名和数据表名不一致而做的配置:
<resultMap id="userMap" type="com.rgb3.domain.User">
<!--主键字段的对应-->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
也可以改为 type=“user”
<resultMap id="userMap" type="user">
<!--主键字段的对应-->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<package>
<typeAliases>
<!--指定要配置别名的包,该包下的实体类都会注册别名,它的类名就是别名,不区分大小写-->
<package name="com.rgb3.domain"></package>
</typeAliases>
在SqlMapConfig.xml 里也有一个<package>
<!--指定映射配置文件的位置,即每个dao独立的配置文件-->
<mappers>
<!--xml形式-->
<!--<mapper resource="com/rgb3/dao/IUserDao.xml"/>-->
<!--注解形式-->
<!--<mapper class="com.rgb3.dao.IUserDao"/>-->
<!-- package 指定 dao 接口所在包,可以代替<mapper>-->
<package name="com.rgb3.dao"></package>
</mappers>
这里的<package>有个前提,dao 接口的 java 文件名要和 xml 文件名一样。
验证一下,现在dao 接口的 java 文件名要和 xml 文件名不一样
运行报错
现在修改为 dao 接口的 java 文件名要和 xml 文件名一样
可以执行。