myBatis框架之入门(一)
框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。
框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。
解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率。
企业级大型项目开发,避免大炮打蚊子。
怎么使用框架
Java的框架是具有一些共性
-
导入jar包
-
框架运行细节定义,也就是编写配置文件(xml)
-
调用框架中的api
原生JDBC案例
-
-
以List集合形式返回
-
编写pojo类 (User)
-
domain,pojo本质都是相同的
domain中的User类
package com.qingmu.domain; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 19:53 2019/3/21 */ public class User { private int id; private String username; private String sex; private String birthday; private String address; @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", birthday='" + birthday + '\'' + ", address='" + address + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } 数据库的结构为:
Dao层的接口
package com.qingmu.Dao; import com.qingmu.domain.User; import java.sql.SQLException; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 19:55 2019/3/21 */ public interface UserDao { List<User> userList() throws ClassNotFoundException, SQLException; }
Dao层的实现类
package com.qingmu.Dao.Iml; import com.qingmu.Dao.UserDao; import com.qingmu.domain.User; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 19:56 2019/3/21 */ /** * 原生的jdbc的开发步骤为: * 1.获取驱动 * 2.获取连接 * 3.获取操作sql语句的对象 * 4.获取结果集 * 5.处理结果集 * 6.释放资源 */ public class UserDaoImpl implements UserDao { // 将driverClass,url,username,password作为这个类的成员变量 private String driverClass = "com.mysql.jdbc.Driver"; private String url = "jdbc:mysql://localhost:3306/mybatis?CharacterEncoding=utf-8"; private String username = "root"; private String password = "root"; /** * 查询数据中的所有数据 * * @return * @throws ClassNotFoundException * @throws SQLException */ @Override public List<User> userList() throws ClassNotFoundException, SQLException { // 创建一个集合,将所有的结果集存储在list集合中, List<User> list = new ArrayList<User>(); // 注册驱动,使用反射进行加载 Class.forName(driverClass); // 获取连接 Connection connection = DriverManager.getConnection(url, username, password); // 获取执行sql语句的对象 String sql = "select * from user"; PreparedStatement psmt = connection.prepareStatement(sql); // 获取结果集 ResultSet rs = psmt.executeQuery(); User user = null; // 处理结果集 while (rs.next()) { user = new User(); // 将结果集中的数据通过getObject()的方法取出来,存到javaBean中 user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setBirthday(rs.getString("birthday")); user.setSex(rs.getString("sex")); user.setAddress(rs.getString("address")); list.add(user); } // 释放资源. rs.close(); psmt.close(); connection.close(); // 返回集合 return list; } }
Test类:
package com.qingmu; import com.qingmu.Dao.Iml.UserDaoImpl; import com.qingmu.Dao.UserDao; import com.qingmu.domain.User; import org.junit.Test; import java.sql.SQLException; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 20:06 2019/3/21 */ public class MainTest { @Test public void testJdbc() throws SQLException, ClassNotFoundException { UserDao userDao = new UserDaoImpl(); List<User> users = userDao.userList(); for (User user : users) { System.out.println(user); } } }
原生JDBC案例的问题
频繁连接,释放数据库资源,
降低系统性能SQL语句硬编码,
难以维护参数和占位符对应问题
结果集解析复杂,列名硬编码
MyBatis框架
Mybatis原本是Apache软件基金会的一个开源项目叫做iBatis,2010年这个项目由
Apache迁移到了goole code管理才改名为Mybatis,2013年又迁移到了GitHub。
Mybatis是一个优秀的持久层框架(Dao层框架),它是对JDBC的封装,使得开发者只需
要关注Sql语句(业务)本身即可,无需开发者处理加载驱动、获取连接、创建
Statement等繁琐的过程。
Mybatis最大的特点是把Sql语句写在XML配置文件当中。而且Mybatis执行完Sql语句之
后可以以对象形式返回(POJO/POJO集合等)。
Mybatis是一个实现了ORM思想的持久层框架。
ORM:Object/Relation Mapping 对象/关系映射。
ORM思想:将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对
对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来
操作数据库。
比如:原来insert使用的是insert into…,如果使用实现了ORM思想的持久层框架,就可
以在Java程序中直接调用api,比如insert(User),达到操作对象即操作数据库的效果。
Hibernate框架是一个全自动的ORM持久层框架,只需要编写POJO,在xml中定义好
Pojo属性和数据表字段的映射/对应关系,就可以在java中实现类似 insert(User)的操
作。Sql语句都不用写。但是因为性能等问题,市场占有率越来越低
Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的
操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框
架。
自定义MyBatis框架:
完整性和严谨性不能和真实的相比,只是自己按照MyBatis框架的思想,将这个过程进行的一个简单的拼接.
上图为实现MyBatis时候的结构思路图:
这是代码的结构图
开始上代码:
pom.xml的依赖为
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.qingmu</groupId> <artifactId>mybatis_qingmu_328</artifactId> <version>1.0-SNAPSHOT</version> <name>mybatis_qingmu_328</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!--使用xpath引入--> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.6</version> </dependency> <!--使用dom4j解析--> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> </build> </project>
pojo包下的三个类:
配置文件类
Configuration
package com.qingmu.pojo; import java.util.HashMap; import java.util.Map; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:21 2019/3/28 */ public class Configuration { private String driver; private String url; private String username; private String password; /** * * Map集合键,通过namespace+"."+id 锁定唯一SQL语句 * * Map集合值,Mapper对象,封装结果集pojo和SQL语句 * */ private Map<String, Mapper> map = new HashMap<String, Mapper>(); public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Configuration{" + "driver='" + driver + '\'' + ", url='" + url + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + ", map=" + map + '}'; } public Map<String, Mapper> getMap() { return map; } public void setMap(Map<String, Mapper> map) { this.map = map; } }
User类
package com.qingmu.pojo; import java.util.Date; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 21:10 2019/3/28 */ public class User { private int id; private String username; private String sex; private Date birthday; private String address; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", birthday='" + birthday + '\'' + ", address='" + address + '\'' + '}'; } }
Mapper类:
package com.qingmu.pojo; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:47 2019/3/28 */ public class Mapper { private String sql; private String resultType; @Override public String toString() { return "Mapper{" + "sql='" + sql + '\'' + ", resultType='" + resultType + '\'' + '}'; } public String getSql() { return sql; } public void setSql(String sql) { this.sql = sql; } public String getResultType() { return resultType; } public void setResultType(String resultType) { this.resultType = resultType; } }
resource包中的两个配置文件
SqlMapConfig文件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
UserMapper文件
<?xml version="1.0" encoding="utf-8" ?> <mapper namespace="test"> <select id="queryUserList" resultType="com.qingmu.pojo.User"> select * from user </select> </mapper>
fram包下的三个类
sqlsessionFactoryBuilder类
package com.qingmu.fram; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:20 2019/3/28 */ import com.qingmu.pojo.Configuration; import com.qingmu.pojo.Mapper; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.util.List; /** * sqlSessionFactory工厂构建者 * 读取xml文件 */ public class SqlSesisonFactoryBuilder { /** * 返回sqlsessionFactory工厂 * 接收一个字节输入流 * 用户携带流 */ public SqlSessionFactory builder(InputStream inputStream) { // 创建一个工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(); // 获取配置文件对象,读取sqlMapperConfig.xml文件 Configuration configuration = loadXmlconfig(inputStream); // 将配置文件对象,传入到sqlSessionFactory中 sqlSessionFactory.setConfiguration(configuration); return sqlSessionFactory; } /** * 解析xml文件用来装配配置对象 * * @param inputStream * @return */ private Configuration loadXmlconfig(InputStream inputStream) { // 获取配置文件对象 Configuration configuration = new Configuration(); // 使用dom4j读取文件 SAXReader saxReader = new SAXReader(); try { // 读取xml文件,获取到document对象 Document document = saxReader.read(inputStream); // 获取根标签 Element rootElement = document.getRootElement(); // 使用xpath表达式读取文件(可以读取节点) List<Element> list = rootElement.selectNodes("//property"); if (list != null && list.size() > 0) { for (Element element : list) { // 属性值 String name = element.attributeValue("name"); String value = element.attributeValue("value"); if ("driver".equals(name)) { configuration.setDriver(value); } else if ("url".equals(name)) { configuration.setUrl(value); } else if ("password".equals(name)) { configuration.setUsername(value); } else if ("username".equals(name)) { configuration.setPassword(value); } } } // 解析mapper标签 List<Element> list1 = rootElement.selectNodes("//mapper"); if (list1 != null && list1.size() > 0) { for (Element element : list1) { // 获取出来xml文件名字,用来绑定流对象,用来读取文件 String resource = element.attributeValue("resource"); // 解析UserMapper文件的方法 loadSqlConfig(resource, configuration); } } } catch (Exception e) { e.printStackTrace(); } return configuration; } /** * 解析UserMapper文件的方法 * @param resource * @param configuration */ private void loadSqlConfig(String resource, Configuration configuration) { // 用来绑定流对象,用来读取文件 InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource); SAXReader saxReader = new SAXReader(); try { // 获取出来doucument对象 Document document = saxReader.read(inputStream); // 获取根标签 Element rootElement = document.getRootElement(); // 使用根标签获取出来namespace属性 String namespace = rootElement.attributeValue("namespace"); // 获取节点 List<Element> list = rootElement.selectNodes("//select"); if (list != null && list.size() > 0) { for (Element element : list) { // 获取标签内的文本(sql) String sql = element.getText(); // 获取结果类型 String resultType = element.attributeValue("resultType"); // 获取出来id String id = element.attributeValue("id"); Mapper mapper = new Mapper(); mapper.setSql(sql); mapper.setResultType(resultType); configuration.getMap().put(namespace + "." + id, mapper); } } } catch (Exception ex) { ex.printStackTrace(); } } }
sqlSessionFacyory类
package com.qingmu.fram; import com.qingmu.pojo.Configuration; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:19 2019/3/28 */ public class SqlSessionFactory { private Configuration configuration; public void setConfiguration(Configuration configuration) { this.configuration = configuration; } /** * 获取出来sqlSession对象 */ public SqlSession openSession(){ return new SqlSessionImpl(configuration); } }
sqlSession接口
package com.qingmu.fram; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:58 2019/3/28 */ public interface SqlSession { public <T> List<T> selectList(String sqlId) throws ClassNotFoundException, SQLException, IllegalAccessException, InstantiationException, InvocationTargetException; }
sqlSession实现类
package com.qingmu.fram; import com.qingmu.pojo.Configuration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:57 2019/3/28 */ public class SqlSessionImpl implements SqlSession { // xml文件配置对象 private Configuration configuration; private String driverClass ; private String url ; private String username ; private String password ; //使用构造方法进行初始化 public SqlSessionImpl(Configuration configuration) { this.configuration = configuration; driverClass = configuration.getDriver(); url = configuration.getUrl(); username = configuration.getUsername(); password = configuration.getPassword(); } @Override public <T> List<T> selectList(String sqlId) throws ClassNotFoundException, SQLException, IllegalAccessException, InstantiationException, InvocationTargetException { // 创建一个空的集合,用来存储需要存放的元素 List<T> arrayList = new ArrayList<T>(); // 使用反射获取驱动 Class.forName(driverClass); // 获取连接 Connection connection = DriverManager.getConnection(url, username, password); // 获取到sql语句 String sql = configuration.getMap().get(sqlId).getSql(); // 创建操作sql语句的对象 PreparedStatement psmt = connection.prepareStatement(sql); // 获取结果集 ResultSet resultSet = psmt.executeQuery(); // 获取出来元数据 ResultSetMetaData metaData = resultSet.getMetaData(); // 创建一个集合用来存储列名 ArrayList<String> cloumnNamelist = new ArrayList<>(); // 如果小于的话,会少最好一列(获取到列的总数为metaData.getColumnCount()) for(int i=1;i<=metaData.getColumnCount();i++){ // 获取出来列名,并存储到集合中 cloumnNamelist.add(metaData.getColumnName(i)); } Object obj = null; // 配置文件,获取结果集封装的pojo对象的全限定名 String resultType = configuration.getMap().get(sqlId).getResultType(); // 使用反射获取出来User类 Class<?> clazz = Class.forName(resultType); // 通过反射获取到方法(表示类或者接口声明的所有方法.) Method[] methods = clazz.getDeclaredMethods(); // 处理结果集 while(resultSet.next()){ // 反射创建对象 obj = clazz.newInstance(); // 遍历集合,获取列名 for (String cloumnName : cloumnNamelist) { // 通过列名,获取到列中所对应的值 Object columvalue = resultSet.getObject(cloumnName); System.out.println(columvalue); // 遍历方法数组 for (Method method : methods) { // 获取到方法名 String methodName = method.getName(); // 判断列名是否和set+方法名相同 if(methodName.equalsIgnoreCase("set"+cloumnName)){ // 调用方法,并进行传参 method.invoke(obj,columvalue); } } } // 对象存储到集合 arrayList.add((T)obj); } return arrayList; } }
Test类
package com.qingmu; import com.qingmu.fram.SqlSesisonFactoryBuilder; import com.qingmu.fram.SqlSession; import com.qingmu.fram.SqlSessionFactory; import com.qingmu.pojo.User; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; import java.util.List; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 21:13 2019/3/28 */ public class ATest { @Test public void mybatisTest() throws ClassNotFoundException, SQLException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException { // 创建工厂创建者对象 SqlSesisonFactoryBuilder sqlSesisonFactoryBuilder = new SqlSesisonFactoryBuilder(); // 使用本类,类加载器获取流,并且绑定 读取sqlMapConfig.xml文件 InputStream inputStream = ATest.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml"); // 使用工厂创建者对象,传入流,创建工厂对象 SqlSessionFactory sqlSessionFactory = sqlSesisonFactoryBuilder.builder(inputStream); // 调用对象,创建sqlsession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 使用selectList方法,传入唯一标识,获取到一个集合. List<User> userList = sqlSession.selectList("test.queryUserList"); if(userList != null && userList.size() > 0){ for(User user : userList){ System.out.println(user); } } inputStream.close(); } }
最后的结果为:
本文来自博客园,作者:King-DA,转载请注明原文链接:https://www.cnblogs.com/qingmuchuanqi48/p/10574707.html