您的位置:首页 > 其它

Mybatis学习笔记之二:在项目中使用Mybatis

2017-07-09 22:36 369 查看
在开发之前,需要做好以下准备工作:

1、JDK以及IDE已经配置完成

2、数据库安装完成

3、相关依赖(Mybatis的jar文件以及JDBC的驱动)

笔者这儿使用的是JDK8,开发工具STS,数据库Mysql 5.6.26,Mybatis版本3.3。

准备好上诉工作就可以开始编写了。

1、创建数据库以及表



2、创建项目并将依赖的jar包加入到类路径中。

3、编写mybatis的配置文件mybatis-config.xml(名字可以随意命名)以及数据库连接配置文件

db.properties

url = jdbc:mysql://localhost:3306/ym_mybatis
user = root
password = 951001
driver = com.mysql.jdbc.Driver
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>
<!--这个properties可以引入外部的配置文件  -->
<properties resource="jdbc.properties"/>
<!--配置别名,后面会讲有什么作用  -->
<typeAliases>
<package name="cn.yamikaze.model"/>
</typeAliases>
<!--配置默认的开发環境  -->
<environments default="development">
<!--可以配置多个开发环境,但是外层的默认开发环境必须是配置的其中一个环境  -->
<environment id="development">
<!--配置事务管理,这儿使用JDBC的事务  -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--配置与数据库的连接  -->
<!--使用${}获取前面引入的配置文件中的值  -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--配置实体类的映射文件(实体类的sql语句存放的文件)-->
<mappers>
<mapper resource="cn/yamikaze/model/UserMapper.xml"/>
</mappers>
</configuration>


4、编写实体类(略)以及实体类的配置文件,配置文件名最好以mapper结尾。
UserMapper.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="org.yamikaze.dao.impl.IUserDao"><!--命名空间不能重复-->
<!--insert、update、delete、select标签分别对应数据库的相应语句,在同一个配置文件中id属性必须唯一
parameterType表示传进来的参数类型,Mybatis内置了一些类型,比如int、map、string等。而useGenerateKeys
表示会使用JDBC的getGeneratedKeys方法取出数据库自动递增的主键。如果配置了keyProperty属性,
会自动将取出来的主键注入到keyProperty配置的属性中,但这只对insert和update有效-->
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
<!--#{}表示一个占位符,类似于JDBC中PreparedStatement的setParameter方法,
中间的值会在传进来的对象中自动查找,例如user对象中有username属性,那么使用#{username}
就会到user中查找username属性,如果没有找到,就会抛出错误-->
insert into t_user(username,password,sex) values(#{username},#{password},#{sex})
</insert>
<select id="loadByUsername" parameterType="string" resultType="User">
SELECT * FROM  t_user WHERE username = #{username}
</select>
</mapper>
还记得在Mybatis-config.xml中配置的typeAliases吗?这儿我们写的参数对象是User,因为配置了别名,所以不用写出User的全称限定名。前面配置的是package=org.yamikaze.model,那么这个包下面的所有类都可以直接使用简单名称。当然你也可以使用typeAlias配置别名,如果有多个实体类包,配置多个package。
userMapper配置文件只写了插入和查找,可以自己补全删除、更新语句。

5、使用Mybatis操纵数据

    使用Mybatis有好几种方式,先介绍最基本的。

    5.1、直接使用Mybatis的session进行操作。

public static void main(String[] args) {
insert();
}

public static void insert() {
InputStream is = null;
SqlSessionFactory factory = null;
SqlSession session = null;
try {
/*读取Mybatis的配置文件,这儿使用的是Mybatis的Resources类,但你可以使用InputStream*/
is = Resources.getResourceAsStream("mybatis-config.xml");
/*通过配置文件获取Mybatis的工场*/
factory = new SqlSessionFactoryBuilder().build(is);
/*通过工场打开一个会话*/
session = factory.openSession();
/*创建实体类对象,并设入相应属性*/
User user = new User();
user.setUsername("zs3");
user.setPassword("123");
user.setSex("man");
/*由于是插入数据,这儿使用insert方法,相应的有selectOne方法、selectList、delete方法*/
/*第一个参数表示哪个命名空间里的哪个方法(配置中填写的id属性,所以一个配置文件不能有相同的id)
* user是传递的参数*/
session.insert("org.yamikaze.dao.impl.IUserDao.save",user);
/**
* 注意:如果调用的方法会修改数据库的数据,一定要记得提交,因为Mybatis使用的是JDBC的事务,
* JDBC是默认自动提交事务的
* 但Mybatis在通过JDBC获取连接时关闭了自动提交
*/
session.commit();
/*因为设置了useGeneratedKeys和keyProperty属性,会自动将ID注入到user对象中*/
System.out.print(user.getId());
} catch (IOException e) {
/*修改数据时发生异常记得回滚数据*/
if(session!=null) session.rollback();
} finally {
/*关闭session*/
if(session!=null) session.close();
}
}
    5.2、使用类的方式,并且对5.1的方式简化一下,因为在整个程序运行期间,可能会获取多个session,但是读取配置和获取工厂只会获取一次,所以我们可以将这部分提取出来。
    先写一个工具类SqlSessionUtil.java

package org.yamikaze.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
* Created by yamikaze
*/
public class SqlSessionUtil {

private static SqlSessionFactory factory;

private SqlSessionUtil(){}

static {
init();
}

private static void init(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
//
System.out.println("读取配置错误");
}
}

public static SqlSession openSession() {
return factory.openSession();
}

public static void closeSession(SqlSession session) {
if(session!=null) session.close();
}

public static void rollback(SqlSession session) {
if(session!=null) session.rollback();
}
}
    编写DAO
    IUserDao.java

package org.yamikaze.dao.impl;

import org.yamikaze.model.User;

/**
* Created by yamikaze on 2017/7/5.
*/
public interface IUserDao {

public void save(User user);
public User loadByUsername(String us
4000
ername);
}

实现类UserDao.java

package org.yamikaze.dao.impl;

import org.apache.ibatis.session.SqlSession;
import org.yamikaze.model.User;
import org.yamikaze.utils.SqlSessionUtil;

import java.io.IOException;

/**
* Created by yamikaze on 2017/7/11.
*/
public class UserDao implements  IUserDao{

@Override
public User loadByUsername(String username) {
return null;
}

@Override
public void save(User user) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
session.insert("org.yamikaze.dao.impl.IUserDao.save",user);
session.commit();
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
SqlSessionUtil.closeSession(session);
}

}
}
save方法变得简单了,但现在问题是session的insert方法需要一个id,向上面那样写肯定是不方便的,我们知道org.yamikaze.dao.impl.IUserDao是命名空间,而save是id,如果所有的mapper配置文件中没有重复的id,可以不加上命名空间,如果有就要加上命名空间,但是这种加法不是很方便,我们可以将命名空间改为实体类的全称限定名,然后在代码中使用这种方式:

@Override
public void save(User user) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
session.insert(User.class.getName()+".save",user);//与调用session.insert("org.yamikaze.model.User.save",user);是一致的
session.commit();
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
SqlSessionUtil.closeSession(session);
}

}
这种方式又有一个问题存在,那就是每个实体类都会有save、delete、update等共通的方法,然后你会发现,就方法的参数以及id不同,那么可以使用以下方式再简化一下:

我们约定统一配置,插入数据id为save、删除delete、更新update、列表list。然后编写一个IBaseDao.java

package org.yamikaze.dao.impl;

import java.util.List;

/**
* Created by yamikaze on 2017/7/11.
*/
public interface IBaseDao<T> {

void save(T t);

void update(T t);

void delete(int id);

T load(int id);

List<T> listAll();
}

这儿使用了泛型,因为不知道实际添加时是什么类型的对象。

继续编写BaseDao.java
package org.yamikaze.dao.impl;

import org.apache.ibatis.session.SqlSession;
import org.yamikaze.utils.SqlSessionUtil;

import java.lang.reflect.*;
import java.util.List;

/**
* Created by yamikaze on 2017/7/11.
*/
public class BaseDao <T> implements IBaseDao<T>{

private Class clz;

/**
* 获取T.class对象,
* @return
*/
protected Class getClz() {
Type genType = getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
clz = (Class) params[0];
return clz;
}

@Override
public T load(int id) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
return session.selectOne(getClz().getName()+".load",id);
//查找数据,可以不用提交
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
}
return null;
}

@Override
public List<T> listAll() {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
return session.selectList(getClz().getName()+".listAll");
} catch (Exception e) {
} finally {
SqlSessionUtil.closeSession(session);
}
return null;
}

@Override
public void save(T t) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
session.insert(getClz().getName()+".save",t);
session.commit();
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
SqlSessionUtil.closeSession(session);
}

}

@Override
public void delete(int id) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
session.delete(getClz().getName()+".delete",id);
session.commit();
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
SqlSessionUtil.closeSession(session);
}
}

@Override
public void update(T t) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
session.update(getClz().getName()+".update",t);
session.commit();
} catch (Exception e) {
SqlSessionUtil.rollback(session);
} finally {
SqlSessionUtil.closeSession(session);
}
}
}
IBaseDao与BaseDao是针对所有对象的共通的CRUD方法。
继续编写IUserDao.java

package org.yamikaze.dao.impl;

import org.yamikaze.model.User;

/**
* Created by yamikaze on 2017/7/5.
*/
public interface IUserDao extends IBaseDao<User>{
User loadByUsername(String username);
}


这个接口中什么方法也没有,因为公共方法已经写进IBaseDao中了,我们可以在这里面写User对象独有的方法,这儿继承IBaseDao需要指定具体实现类型。

编写UserDao.java

package org.yamikaze.dao.impl;

import org.apache.ibatis.session.SqlSession;
import org.yamikaze.model.User;
import org.yamikaze.utils.SqlSessionUtil;

import java.io.IOException;

/**
* Created by yamikaze on 2017/7/11.
*/
public class UserDao extends BaseDao<User> implements  IUserDao{

public User loadByUsername(String username) {
SqlSession session = null;
try {
session = SqlSessionUtil.openSession();
return session.selectOne(getClz().getName()+".loadByUsername",username);
} catch(Exception e) {

} finally {
SqlSessionUtil.closeSession(session);
}
return null;
}

}
因为公共方法的实现在BaseDao中实现了,所以我们只实现IUserDao中的方法

接下来做下测试吧!

package org.yamikaze.test;

import org.yamikaze.dao.impl.IUserDao;
import org.yamikaze.dao.impl.UserDao;
import org.yamikaze.model.User;

/**
* Created by yamikaze on 2017/7/11.
*/
public class UserDaoTest {

public static void main(String[] args) {
IUserDao userDao = new UserDao();
User u = new User();
u.setUsername("tom");
u.setSex("man");
u.setPassword("951001");
userDao.save(u);
}
}
测试结果



成功了,让我们看看下一种使用方式吧!

    5.3、使用接口

              在5.2中使用的是类,Mybatis还提供了一种接口的使用方式。

     使用方式如下:

public static void insert() {
InputStream is = null;
SqlSessionFactory factory = null;
SqlSession session = null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
session = factory.openSession();
IUserDao userDao = session.getMapper(IUserDao.class);
User user = new User();
user.setUsername("zs3");
user.setPassword("123");
user.setSex("man");
userDao.save(user);
session.commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(session!=null) session.close();
}
}
可以看出与使用类的方式相差不大,但是不同的是我们调用的是借口里面的方法。

与使用类一致,也可以写一个IBaseDao来简化代码,这儿就不再赘述了。接口里面的方法要与配置文件中的id相对应,如果接口方法名不存在于配置文件中会报错。

这种方式可以有代码提示,即到底配置文件中有哪些sql语句(前提是保证接口中方法与配置文件中id一一对应)。

特别注意:session.getMapper(class类型)中的class类型

例如:IUserDao的全称限定名是org.yamikaze.dao.impl.IUserDao,那么userMapper配置文件中的命名空间就一定是这个字符串,否则会报错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: