MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
1.准备开发环境
1、创建测试项目,普通java项目或者是JavaWeb项目均可,如下图所示:
添加相应的jar包:
mybatis-3.4.4.jar
mysql-connector-java-5.1.30-bin.jar
jsbc.prop[mysql数据库信息配置文件]:
#dbConfig
#Mon Jul 31 07:54:49 CST 2017
url=jdbc:mysql://localhost:3306/t_market
password=root
driver=com.mysql.jdbc.Driver
username=root
mybatis-config.xml[mybatis配资信息文件]:
<?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和java的.properties的配置文件有关;
配置properties的resource指定.properties的路径;
然后再在properties标签下配置property的name和value,
则可以替换.properties文件中相应属性值。 -->
<properties resource="jsbc.prop" />
<!--typeAliases 必须在properties之后声明 -->
<!-- typeAliases类型别名,类型别名是Java 类型的简称;它仅仅只是关联到XML 配置,简写冗长的JAVA 类名; -->
<typeAliases>
<!-- 定义别名User为javaBean类com.my.market.model.User -->
<typeAlias alias="User" type="com.my.market.model.User"/>
</typeAliases>
<!-- environments环境,MyBatis 可以配置多个环境。这可以帮助你SQL 映射对应多种数据库等; -->
<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>
<!-- 将model中类对应的mapper文件加入配置中-->
<!-- mappers映射器,这里是告诉MyBatis 去哪寻找映射SQL 的语句;可以使用类路径中的资源引用,或者使用字符,输入确切的URL引用; -->
<mappers>
<mapper resource="com/my/market/model/User.xml"/>
</mappers>
</configuration>
2.定义表所对应的实体类,如下图所示:
User.java[实体类User]:
package com.my.market.model;
public class User {
private int id;
private String username;
private String password;
private String nickname;
private int type;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public User(int id, String username, String password, String nickname, int type) {
this.id = id;
this.username = username;
this.password = password;
this.nickname = nickname;
this.type = type;
}
public User() {
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", nickname=" + nickname
+ ", type=" + type + "]";
}
}
User.xml[User类对应的Mapper文件]:
<?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">
<!-- com.my.market.model.User实体类对应的mapper文件,namespace限定名字空间避免重复 -->
<mapper namespace="com.my.market.model.User">
<!-- 通过[namespace.id 即 com.my.market.model.User.add]进行add的插入方法的调用 -->
<insert id="add" parameterType="User">
insert into t_user(username, password, nickname, type)
values(#{username},#{password},#{nickname},#{type})
</insert>
<update id="update" parameterType="User">
update t_user set password=#{password},nickname=#{nickname},type=#{type} where id=#{id}
</update>
<delete id="delete" parameterType="int">
delete from t_user where id=#{id}
</delete>
<select id="select" parameterType="int" resultType="User">
select * from t_user where id=#{id}
</select>
<!-- 使用User别名 -->
<select id="list" resultType="User">
select * from t_user
</select>
</mapper>
3.Junit测试类
MyBatisUtil.java[Mybatis工具类用来获取session]:
package com.my.market.util;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static final String RESOURCE = "mybatis-config.xml";
private static SqlSessionFactory factory;
static {
try {
//1.创建配置文件(mybatis-config.xml)的输入流
InputStream iStream=Resources.getResourceAsStream(RESOURCE);
//2.创建SqlSessionFactory
factory=new SqlSessionFactoryBuilder().build(iStream);
} catch (IOException e) {
e.printStackTrace();
}
}
private MyBatisUtil() {
}
public static SqlSession getSession() {
//3.创建SqlSession
return factory.openSession();
}
public static void close(SqlSession session) {
if(null!=session) {
session.close();
}
}
}
TestMyBatisJunit.java[MyBatis Junit测试类]:
package com.my.market.test;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.jws.soap.SOAPBinding.Use;
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 org.junit.Test;
import com.my.market.model.User;
import com.my.market.util.MyBatisUtil;
public class TestMyBatisJunit {
private static final String RESOURCE = "mybatis-config.xml";
@Test
public void testDelete() {
InputStream is=null;
try {
is = Resources.getResourceAsStream(RESOURCE);
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
SqlSession session=factory.openSession();
System.out.println(User.class.getName());
session.delete(User.class.getName()+".delete", 9);
session.commit();
session.close();
}
@Test
public void testLoad() {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
User user=(User)session.selectOne(User.class.getName()+".select", 1);
System.out.println(user);
}finally {
MyBatisUtil.close(session);
}
}
@Test
public void testAdd() {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
User user=new User(0, "tangseng1", "123", "唐僧1", 0);
session.insert(User.class.getName()+".add", user);
session.commit();
}catch(Exception e) {
session.rollback();
e.printStackTrace();
}
finally {
session.close();
}
}
@Test
public void testList() {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
List<User> userList=session.selectList(User.class.getName()+".list");
for(User u: userList) {
System.out.println(u);
}
}finally {
MyBatisUtil.close(session);
}
}
}
4.工具,基础类
1.BaseDao.java[所有dao的基本父类]:
package com.my.market.dao;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import com.my.market.model.Address;
import com.my.market.model.Page;
import com.my.market.model.SystemContext;
import com.my.market.model.User;
import com.my.market.util.DBUtil;
import com.my.market.util.DaoUtil;
import com.my.market.util.LogUtil;
import com.my.market.util.MyBatisUtil;
public class BaseDao<T> {
public BaseDao() {
// //依赖注入,对于子类需要set的对象,例如setUserDao
// Method[] methods=this.getClass().getDeclaredMethods();
// //error:unknow function
// //this.setUserDao(null);
// System.out.println(Arrays.toString(methods));
// for(Method m: methods) {
// String methodName =m.getName();
// if(methodName.startsWith("set")) {
// LogUtil.printLog(m);
// String name=methodName.substring(3);
// LogUtil.printLog(methodName+": "+name);
// Object obj=DaoUtil.createDaoFactory().getDao(name);
// try {
// m.invoke(this, obj);
// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// e.printStackTrace();
// }
// }
// }
DaoUtil.diDao(this);
}
public void add(T obj) {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
session.insert(obj.getClass().getName()+".add", obj);
session.commit();
}catch(Exception e) {
session.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.close(session);
}
}
public <Type> void add(String sqlId, Type obj) {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
session.insert(sqlId, obj);
session.commit();
}catch(Exception e) {
session.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.close(session);
}
}
public void update(T obj) {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
session.update(obj.getClass().getName()+".update", obj);
session.commit();
}catch(Exception e) {
session.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.close(session);
}
}
public void delete(Class<T> clz, int id) {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
session.delete(clz.getName()+".delete", id);
session.commit();
}catch(Exception e){
session.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.close(session);
}
}
public void delete(String sqlId, Map<String, Object> params) {
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
session.delete(sqlId, params);
session.commit();
}catch(Exception e){
session.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.close(session);
}
}
public T load(Class<T> clz, int id) {
SqlSession session=null;
T obj=null;
try {
session=MyBatisUtil.getSession();
obj= session.selectOne(clz.getName()+".load", id);
}finally {
MyBatisUtil.close(session);
}
return obj;
}
public T loadBySqlId(String sqlId, Map<String, Object> params) {
SqlSession session=null;
T obj=null;
try {
session=MyBatisUtil.getSession();
obj= session.selectOne(sqlId, params);
}finally {
MyBatisUtil.close(session);
}
return obj;
}
public T loadBySqlId(String sqlId, Object param) {
SqlSession session=null;
T obj=null;
try {
session=MyBatisUtil.getSession();
obj= session.selectOne(sqlId, param);
}finally {
MyBatisUtil.close(session);
}
return obj;
}
public Page<T> find(Class<T> clz, Map<String, Object> params){
int pageSize =SystemContext.getMaxPageItems();
int pagerOffset=SystemContext.getPagerOffset();
String order=SystemContext.getOrder();
String condition=SystemContext.getCondition();
Page<T> page = null;
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
if(null==params) {
params=new HashMap<>();
}
params.put("pageSize", pageSize);
params.put("pagerOffset", pagerOffset);
params.put("order", order);
params.put("condition", condition);
List<T> objList=session.selectList(clz.getName()+".find", params);
int totalRecord=session.selectOne(clz.getName()+".find_count", params);
page=new Page<T>(pagerOffset/pageSize+1, totalRecord, pageSize,
totalRecord/pageSize+(totalRecord%pageSize==0? 0:1), objList);
}finally {
MyBatisUtil.close(session);
}
return page;
}
public Page<T> find(String sqlId, Map<String, Object> params){
int pageSize =SystemContext.getMaxPageItems();
int pagerOffset=SystemContext.getPagerOffset();
String order=SystemContext.getOrder();
String condition=SystemContext.getCondition();
Page<T> page = null;
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
if(null==params) {
params=new HashMap<>();
}
params.put("pageSize", pageSize);
params.put("pagerOffset", pagerOffset);
params.put("order", order);
params.put("condition", condition);
List<T> objList=session.selectList(sqlId, params);
LogUtil.printLog(sqlId);
LogUtil.printLog(sqlId+"_count");
int totalRecord=session.selectOne(sqlId+"_count", params);
page=new Page<T>(pagerOffset/pageSize+1, totalRecord, pageSize,
totalRecord/pageSize+(totalRecord%pageSize==0? 0:1), objList);
}finally {
MyBatisUtil.close(session);
}
return page;
}
public List<T> listBySqlId(String sqlId, Map<String, Object> params){
List<T> objList= null;
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
if(null==params) {
params=new HashMap<>();
}
objList=session.selectList(sqlId, params);
}finally {
MyBatisUtil.close(session);
}
return objList;
}
}
2.DaoUtil.java[工厂模式的获取,依赖注入]:
package com.my.market.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import com.my.market.dao.IFactoryDao;
import com.my.market.model.MarketDi;
public class DaoUtil {
public static void main(String[] args) {
createDaoFactory();
}
public static IFactoryDao createDaoFactory() {
Properties properties= PropertiesUtil.getDaoProp();
String factoryName=properties.getProperty("factory");
LogUtil.printLog(factoryName);
IFactoryDao daoFactory=null;
try {
Class<?> clz=Class.forName(factoryName);
String methodName="getInstance";
Method method=clz.getMethod(methodName);
daoFactory =(IFactoryDao)method.invoke(clz);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LogUtil.printLog(daoFactory);
return daoFactory;
}
public static void diDao(Object obj) {
//get the class from the object which will set value into it
Class<?> clz=obj.getClass();
//get declared methods from the class
Method[] methods=clz.getDeclaredMethods();
for(Method m: methods) {
//if the Method has 'MarketDi' annotation, it show the Method want to get a object
if(m.isAnnotationPresent(MarketDi.class)) {
MarketDi aDi=m.getAnnotation(MarketDi.class);
String objName=aDi.value();
if(null==objName || "".equals(objName)) {
String methodName=m.getName();
LogUtil.printLog(methodName+": "+objName);
if(methodName.startsWith("set")) {
LogUtil.printLog(m);
objName=methodName.substring(3);
}
}
//get className from properties file, invoke the Method, set the object into it
try {
Properties properties=PropertiesUtil.getDaoProp();
String className=properties.getProperty(objName);
LogUtil.printLog(objName+": "+className);
Object object=Class.forName(className).newInstance();
m.invoke(obj, object);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException |
IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
3.PropertiesUtil.java[属性读取工具]:
package com.my.market.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import sun.security.jca.GetInstance;
public class PropertiesUtil {
private static Properties dBProperties=null;
private static Properties daoProperties=null;
private static final String CONFIG_FILE="dbConfi.prop";
private static final String DAO_FILE="dao.prop";
private PropertiesUtil() {
}
public static Properties getInstance() {
if(null==dBProperties) {
synchronized (PropertiesUtil.class) {
if(null==dBProperties) {
dBProperties=new Properties();
// try(
// FileInputStream fin=new FileInputStream("/"+CONFIG_FILE);
// ){
try{
File f1=new File("test.txt");
LogUtil.printLog(f1.getAbsolutePath());
LogUtil.printLog(PropertiesUtil.class.getResource(CONFIG_FILE));
dBProperties.load(PropertiesUtil.class.getResourceAsStream(CONFIG_FILE));
}catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
}
return dBProperties;
}
public static Properties getDaoProp() {
try {
if(null==daoProperties) {
synchronized(PropertiesUtil.class) {
if(null==daoProperties) {
daoProperties=new Properties();
daoProperties.load(PropertiesUtil.class.getClassLoader().getResourceAsStream(DAO_FILE));
}
}
}
}catch(IOException e) {
e.printStackTrace();
}
return daoProperties;
}
}
DaoFactoryByProperties.java[通过properties获取Dao工厂]:
package com.my.market.dao;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import com.my.market.util.LogUtil;
import com.my.market.util.PropertiesUtil;
public class DaoFactoryByProperties implements IFactoryDao {
private static DaoFactoryByProperties factory=new DaoFactoryByProperties();
private static Map<String, Object> daoMap=new HashMap<>();
private DaoFactoryByProperties() {
}
public static IFactoryDao getInstance() {
return factory;
}
@Override
public Object getDao(String name) {
Object object=null;
Properties properties=PropertiesUtil.getDaoProp();
String daoClassName=properties.getProperty(name);
LogUtil.printLog(daoClassName);
if(daoMap.containsKey(daoClassName)) {
return daoMap.get(daoClassName);
}
try {
object=Class.forName(daoClassName).newInstance();
daoMap.put(daoClassName, object);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
}
5.mybatis使用步骤
操作步骤
1、将jar导入到项目
2、创建Config.xml文件用来指定相应的数据库连接信息
3、创建mapp.xml文件
4、创建SqlSessionFactory
5、根据factory获取session
6、直接根据session来执行相应的操作
6.map文件中的insert,update,delete,select
insert标签表示添加相应的对象信息,paramterType表示添加的对象类型
update表示更新操作,delete表示删除操作
select表示查询操作,可以查询列表或者单个对象
相应的调用方式
7.mapp.xml中两种引用
1、#{xxx}这种方式会自动将这个值替换为PreparedStatment中?来使用,如果是字符串会自动加上引号,对于排序而言就无法操作
2、${xx}这种方式叫做完全替换,直接将字符串完整的替换到这个位置,完全替换的方式可能会出现SQL注入的安全隐患。建议在参数中不要使用这种方式。但是如果使用在排序中没有任何影响
8.动态SQL语句
在mapp.xml文件中可能会根据一些参数值的不同而动态的产生相应的SQL语句,此时就需要进行动态SQL语句的设定
9.Resultmap的使用
使用ResultMap可以完成相应的结果集自定义输出
ResultMap还可以完成一些外键对对象的映射
使用以上映射方式有一个致命的缺点:所谓的N+1问题
使用关联查询来解决N+1问题