先展示一下左侧的包和类,有关Student的可以忽略,我在下面代码中也不会体现,只是我自己在写代码时多写的类。
一、添加依赖。
当我们新建一个maven工程后,首先要在pom.xml里面添加依赖,即我们后续工程要用到的jar包。build部分是必不可少的,每个maven工程都要添加。
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>dev.tuxjsql</groupId>
<artifactId>hikaricp-cp</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<target>1.8</target>
<source>1.8</source>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
二、在数据库新建一个表。
id为主键,如下图
三、新建entity.User类
此User类和数据库的user表相对应,对user进行构造函数,getter和setter,toString
public class User {
private int id;
private String username;
private String password;
public User(){}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
四、新建properties
druid.properties
druid.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
druid.username=root
druid.password=123456
druid.driverClassName=com.mysql.cj.jdbc.Driver
hikari.properties
username=root
password=123456
jdbcUrl=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
driverClassName=com.mysql.cj.jdbc.Driver
五、新建dao.UserDao接口
即对user要实现的功能
public interface UserDao {
/**
* 保存用户
* @param user
* @return
*/
Integer saveUser(User user);
/**
* 根据id查找用户
* @param id
* @return
*/
List<User> findUser(Integer id);
}
六、新建mapper.UserMapper.xml
即UserDao的映射
<!--UserDao的映射-->
<mapper namespace="com.xinzhi.dao.UserDao">
<!--id和方法名一样-->
<insert id="saveUser" resultType="com.xinzhi.entity.User" paramType="com.xinzhi.User">
insert into user values(?,?,?)
</insert>
<select id="findUser" resultType="com.xinzhi.entity.User" paramType="com.xinzhi.User">
select * from user where id = ?
</select>
</mapper>
七、新建mybatis-config.xml
这里管理所有的mapper,标签mapper下可添加其他的mapper文件
<!--通过这个文件找到所有相关的Mapper文件-->
<mybatis>
<!--找到数据源-->
<dataSource>druid</dataSource>
<mapper>mapper/userMapper.xml</mapper>
<!--<mapper>mapper/studentMapper.xml</mapper>-->
</mybatis>
八、新建DaoWrapper类
实现序列化,这里的属性对应UserMapper.xml文件
public class DaoWrapper implements Serializable {
/**
* 类型,insert|update|delete
*/
private String type;
/**
* 返回值的类型
*/
private String resultType;
/**
* 参数的类型
*/
private String paramType;
/**
* sql语句
*/
private String sql;
public DaoWrapper(){}
public DaoWrapper(String type, String resultType, String paramType, String sql) {
this.type = type;
this.resultType = resultType;
this.paramType = paramType;
this.sql = sql;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
@Override public String toString() {
return "DaoWrapper{" +
"type='" + type + '\'' +
", resultType='" + resultType + '\'' +
", paramType='" + paramType + '\'' +
", sql='" + sql + '\'' +
'}';
}
}
九、新建DataSourceFactory类,创建数据源
其实这个应该放在前面,因为在写mybatis-config.xml文件时,就要确定是要用druid还是hikari
/**
* 数据源工厂
* 简单工厂的应用
*/
public class DataSourceFactory {
// public static void main(String[] args) {
// // druid为魔术值,阿里规约里面写要避免
// DataSource hikari = DataSourceFactory.createDataSource("druid");
// System.out.println(hikari);
// }
public static final String DARASOURC_TYPE_HIKARI = "hikari";
public static final String DARASOURC_TYPE_DRUID = "druid";
public static DataSource createDataSource(String type){
// 创建数据源
DataSource dataSource = null;
Properties properties = new Properties();
if(DARASOURC_TYPE_HIKARI.equals(type)){
try {
properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("hikari.properties"));
} catch (IOException e) {
e.printStackTrace();
}
HikariConfig hikariConfig = new HikariConfig(properties);
dataSource = new HikariDataSource(hikariConfig);
} else if (DARASOURC_TYPE_DRUID.equals(type)){
try {
properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("druid.properties"));
} catch (IOException e) {
e.printStackTrace();
}
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.configFromPropety(properties);
dataSource = druidDataSource;
}
return dataSource;
}
}
十、新建Session类
public class Session {
/**
* 每个会话都保持一个连接
*/
private Connection connection;
private Map<String, Map<String,DaoWrapper>> env;
public Session(Connection connection, Map<String, Map<String, DaoWrapper>> env) {
this.connection = connection;
this.env = env;
}
// 开始会话
public void begin(){
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 提交
public void commit(){
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 回滚
public void rollback(){
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
public <T> T getMapper(Class clazz) {
T t = (T)Proxy.newProxyInstance(Session.class.getClassLoader(),
new Class[]{clazz}, new SqlInvocationHandler(connection,env.get(clazz.getName())));
return t;
}
}
十一、新建SqlInvocationHandler类
实现InvocationHandler,这个类即Session类最后调用的new SqlInvocationHandler(connection,env.get(clazz.getName()),我们把原本的InvocationHandler抽取出来成了一个类
public class SqlInvocationHandler implements InvocationHandler {
private Connection connection;
private Map<String,DaoWrapper> env;
public SqlInvocationHandler(Connection connection, Map<String, DaoWrapper> env) {
this.connection = connection;
this.env = env;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 拿到包装
DaoWrapper wrapper = env.get(method.getName());
PreparedStatement statement = connection.prepareStatement(wrapper.getSql());
// 对每一种sql语句进行独立的操作
if ("insert".equals(wrapper.getType())) {
String paramType = wrapper.getParamType();
// 暂定传入一个对象
Class<?> clazz = args[0].getClass();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
statement.setObject(i + 1, fields[i].get(args[0]));
}
return statement.executeUpdate();
} else if ("delete".equals(wrapper.getType())) {
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
return statement.executeUpdate();
} else if ("select".equals(wrapper.getType())) {
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
ResultSet result = statement.executeQuery();
List list = new ArrayList();
while (result.next()) {
Class<?> clazz = Class.forName(wrapper.getResultType());
Object object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
fields[i].set(object, result.getObject(fields[i].getName()));
}
list.add(object);
}
return list;
}
return null;
}
}
十二、新建SessionFactory类
public class SessionFactory {
private DataSource dataSource;
/**
* 第一个参数String表示UserMapper里的namespace
* 第二个参数String表示id即方法名
* 第三个参数DaoWrapper表示剩下的所有内容:类型,返回值类型,参数类型,sql语句
*/
private Map<String, Map<String,DaoWrapper>> env = new HashMap<>(8);
public SessionFactory(String configPath) {
parseConfigXml(configPath);
}
/**
* 解析配置文件
* @param configPath
*/
private void parseConfigXml(String configPath) {
try{
// 解析数据源
InputStream resource = SessionFactory.class.getClassLoader().getResourceAsStream(configPath);
SAXReader reader = new SAXReader();
Document read = reader.read(resource);
Element ConfigRoot = read.getRootElement();
Element dataSourceElement = ConfigRoot.element("dataSource");
dataSource = DataSourceFactory.createDataSource(dataSourceElement.getTextTrim());
// 获取所有的mapper文件
List mapperElements = ConfigRoot.elements("mapper");
List<String> mapperPaths = new ArrayList<>();
for (Object mapperElement : mapperElements) {
Element element = (Element) mapperElement;
mapperPaths.add(element.getTextTrim());
}
for (String mapperPath : mapperPaths) {
Map<String, DaoWrapper> wrapper = new HashMap<>(8);
Document document = reader.read(Session.class.getClassLoader().getResourceAsStream(mapperPath));
Element root = document.getRootElement();
String namespace = root.attribute("namespace").getValue();
Iterator iterator = root.elementIterator();
while (iterator.hasNext()) {
Element el = (Element) iterator.next();
String type = el.getName();
String id = el.attribute("id").getValue();
String resultType = el.attribute("resultType").getValue();
String paramType = el.attribute("paramType").getValue();
String sqlStr = el.getTextTrim();
wrapper.put(id, new DaoWrapper(type, resultType, paramType, sqlStr));
}
env.put(namespace, wrapper);
}
}catch (Exception e){
e.printStackTrace();
}
}
public Session openSession(){
try {
Session session = new Session(dataSource.getConnection(),env);
return session;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
十三、测试结果
public class Test {
public static void main(String[] args) {
SessionFactory sessionFactory = new SessionFactory("mybatis-config.xml");
Session session = sessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
// 保存User
//userDao.saveUser(new User(11,"a","b"));
// 查阅User
List<User> user = userDao.findUser(11);
System.out.println(user);
}
}
使用druid连接源
使用hikari连接源