项目下载
该项目包含了代码,所需jar包和sql文件
一、MyBatis简介
MyBatis和Hibernate一样,是一个orm持久层框架。原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装,这样可以让程序员专注于sql语句本身。而且国内目前使用Mybatis的公司比hibernate要多。mybatis相关jar包可自行到官网下载,也可用我项目提供的jar包
二、MyBatis执行流程图
三、MyBatis用传统的DAO实现数据的增删查改
需求:
根据用户ID查询用户信息(精准查询)
根据用户名查找用户列表(模糊查询)
添加用户
修改用户信息
根据用户ID删除用户
思路:
1、创建mysql数据库和建表并创建java项目
2、导入所需的jar包(需要用到 jdbc 的jar包)
3、编写jdbc配置文件 jdbc.properties和向控制台输出内容的日志文件 log4j.properties
4、编写mybatis的配置文件 SqlMapConfig.xml 和 sql 映射文件 user.xml
5、编写 sql 工具类 SqlSessionFactoryUtils.java
6、编写 pojo、dao接口和其实现类
7、编写测试类
项目结构图:
编写程序
前两个步骤在项目文件中有提供,在此就不赘述了
1、创建 jdbc.properties 和 log4j.properties
创建 jdbc.properties
该文件是用来配置数据的连接信息的,如用户名,密码等,可根据自己数据库连接信息不同进行更改。通过此种方式,在后期维护更方便,不用修改代码,改配置文件即可
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
创建 log4j.properties
编写该文件是在运行程序后能够向控制台输出一些有关sql的信息
#指定根目录下的日志级别,log4j为关键字,rootLogger表示应用根目录,console为输出设备
log4j.rootLogger=DEBUG, stdout
#定义上面的输出设备
log4j.appender.stdout=org.apache.log4j.
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2、工具类 SqlSessionFactoryUtils.java
编写该类是抽取部分重复代码,防止代码冗余。值得一提的是,该类中没有返回 SqlSession 对象是因为每一个线程都得使用一个sqlsession,并且sqlsession是不能共享的,它是线程不安全的
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory;
//静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。
//如果一个类中有多个静态代码块,会按照书写顺序依次执行
static {
try {
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 加载配置文件,创建SqlSessionFactory对象
sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
3、创建 SqlMapConfig.xml 和 user.xml
创建 SqlMapConfig.xml 全局配置文件
主要是2个标签:
environments:用于获取数据库连接池连接,与spring整合后 environments 配置将废除。
mappers:用于引用映射文件。
ps: typeAliases标签是定义别名用的(就是在映射文件属性值需要用到比如com.itheima.mybatis.pojo时,可以用别名代替,使代码简介),package标签是别名包扫描器(推荐使用此方式),整个包下的类都被定义别名,别名就是类名,不区分大小写
<?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">
<!-- dtd模式必须严格按照它的模式顺序写代码 ,如mappers必须在environments之后-->
<configuration>
<!-- 加载jdbc文件-->
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="com.itheima.mybatis.pojo"/>
</typeAliases>
<environments default="development">
<!-- 可配置多个environment,若配置多个environment,将 environments的default改动就行,如default="test"-->
<environment id="development">
<!-- 使用jdbc事务管理 -->
<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>
<!-- 传统dao写法只有这种配置方式-->
<mapper resource ="mybatis/user.xml"/>
</mappers>
</configuration>
创建 sql 映射文件 user.xml
ps: namespace是命名空间,类似项目的包,在传统dao中,namespace可随意命名,但在动态代理中,需要写接口的全路径名
{}是占位符,相当于jdbc的?,${}字符串拼接指令,如果时普通的基本类型(如string,double等),只能写value。
对数据进行增删查改对应的标签分别是 insert,delete,select,update。里面的id属性是唯一的标识,方便调用。parameterType属性是入参的类型,传入java类型,转化为sql类型。
resultType是出参的类型,执行sql语句后将sql类型转化为java数据类型并返回。
useGeneratedKeys=“true” keyProperty=“id” 的功能是主键返回,两者要配合使用,keyProperty的值是表中主键的属性名
<?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="user">
<select id="getUserById" parameterType="int" resultType="com.itheima.mybatis.pojo.User">
SELECT * FROM USER WHERE id = #{id}
</select>
<select id="getUserByName" parameterType="string" resultType="com.itheima.mybatis.pojo.User" >
SELECT * FROM USER WHERE username like '%${value}%'
</select>
<insert id="insertUser" parameterType="com.itheima.mybatis.pojo.User" useGeneratedKeys="true" keyProperty="id">
<!--
useGeneratedKeys="true" keyProperty="id" 功能是主键返回
-->
INSERT INTO USER
(`username`,
`birthday`,
`sex`,
`address`)
VALUES (#{username},
#{birthday},
#{sex},
#{address});
</insert>
<update id="updateUser" parameterType="com.itheima.mybatis.pojo.User">
UPDATE USER SET username = #{username} WHERE id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
DELETE FROM `user` WHERE `id` = #{id}
</delete>
</mapper>
4、编写 pojo、dao接口和其实现类
pojo类
package com.itheima.mybatis.pojo;
import java.util.Date;
public class User {
private Integer id;//用户id
private String userName;// 用户名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//省略掉 set 和 get 方法
dao接口
package com.itheima.mybatis.dao;
import java.util.List;
import com.itheima.mybatis.pojo.User;
/**、
* 用户信息持久化接口
* @author zhang
*
*/
public interface UserDao {
/**
* 根据用户ID查询用户信息
* @param id
* @return
*/
User gUserById(Integer id);
/**
* 根据用户名查询用户信息
* @param userName
* @return
*/
List<User> getUserByUserName(String userName);
/**
* 向数据库插入用户
* @param user
*/
void insertUser(User user);
/**
* 修改用户信息
* @param user
*/
void updatetUser(User user);
/**
* 根据ID删除用户
* @param id
*/
void deletetUser(Integer id);
}
实现类
// 只展示部分代码
public class UserDaoImpl implements UserDao {
@Override
public User gUserById(Integer id) {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.getUserById", id);
sqlSession.close(); //关闭sqlSession
return user;
}
@Override
public List<User> getUserByUserName(String userName) {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.getUserByName", userName);
sqlSession.close();
return list;
}
}
4、编写测试类
// 只展示部分代码
public class UserDaoTest {
@Test
public void testGUserById() {
UserDaoImpl userDaoImpl = new UserDaoImpl();
User user = userDaoImpl.gUserById(31);
System.out.println(user);
}
@Test
public void testGetUserByUserName() {
UserDaoImpl userDaoImpl = new UserDaoImpl();
List<User> list = userDaoImpl.getUserByUserName("张");
for(User user:list) {
System.out.println(user);
}
}
}
四、 MyBatis用动态代理实现数据的增删查改(官方推荐)
传统的dao对数据的操作的缺点是,如果接口增加一个方法,所有实现类需要实现这个方法外,增加了代码维护的复杂度。
mybatis 使用动态代理需要符合以下四个要求:
- namespace必须是接口的全路径名
- 接口的方法名必须与映射文件的sql id一致
- 接口的输入参数必须与映射文件的parameterType类型一致
- 接口的返回类型必须与映射文件的resultType类型一致
总结一句话就是接口的全路径名,方法名,参数类型,返回值类型必须和namespace,sql属性id,parameterType,resultType相等
下面用动态代理实现上面例子
1、重新创建包com.itheima.mybatis.mapper,里面存放接口类UserMapper.java和映射文件userMapper.xml(放在同一目录的原因待会引用映射文件要用另一种方式)。接口类只需将刚才的UserDao.java复制过去即可,映射文件只需将
mapper namespace="user"这句改为
mapper namespace="com.itheima.mybatis.mapper.UserMapper"即可
部分代码
<mapper namespace="com.itheima.mybatis.mapper.UserMapper">
<select id="getUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id = #{id1}
</select>
<select id="getUserByUserName" parameterType="string" resultType="user" >
SELECT * FROM USER WHERE username like '%${value}%'
</select>
2、修改SqlMapConfig.xml文件,在mappers下新增 package name=“com.itheima.mybatis.mapper” 即可,name的值为接口的包路经
<!-- 加载映射文件 -->
<mappers>
<!-- 第一种方式,加载 resource 传统dao写法只有这种配置方式-->
<mapper resource ="mybatis/user.xml"/>
<!-- 第二种方式,包扫描器要求(推荐使用此方式):
1、映射文件与接口同一目录下
2、映射文件名必需与接口文件名称一致(不区分大小写)
-->
<package name="com.itheima.mybatis.mapper"/>
</mappers>
3、编写测试类
//部分代码
public class UserMapperTest {
@Test
void testGetUserById() {
// 加载配置得到SqlSession
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
// 获取代理对象,相当于实现类,反射实现
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 查询数据
User user = userMapper.getUserById(31);
System.out.println(user);
// 关闭资源
sqlSession.close();
}
@Test
void testGetUserByUserName() {
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
// 获取代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 查询数据
List<User> list = userMapper.getUserByUserName("张");
for (User user : list) {
System.out.println(user);
}
// 关闭资源
sqlSession.close();
}